From: Marcelo Vanzin Date: Mon, 24 Aug 2009 21:43:39 +0000 (-0700) Subject: 2009.08.24-187411 X-Git-Tag: 2009.08.24-187411 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cfead6f29409b79d6e671a1c3e1b019ea2a0fc44;p=thirdparty%2Fopen-vm-tools.git 2009.08.24-187411 --- diff --git a/open-vm-tools/ChangeLog b/open-vm-tools/ChangeLog index 1dc113ec9..410e32371 100644 --- a/open-vm-tools/ChangeLog +++ b/open-vm-tools/ChangeLog @@ -1,3 +1,115 @@ +2009-08-24 Marcelo Vanzin + * Resync with internal trunk (2009.08.19) + + * configure.ac: remove support for Linux kernels < 2.6.9. + + * lib/include/vmtools.h, libvmtools/vmtoolsLog.c, doc/api/services/util.txt: + add new log handled that allows appending to existing log files, and fix + an issue where old log files would be "rotated" whenever the config file + was reloaded. + + * lib/appUtil/appUtilX11.c, lib/ghIntegration/ghIntegrationX11.c, + lib/include/appUtil.h: fix compilation issues on FreeBSD when unity + was enabled. + + * lib/dnd/dndLinux.c, lib/include/vmblock_user.h, tests/testVmblock/*: add + vmblock tests and, as part of the change, do some refactoring of vmblock + related functions. + + * lib/guestInfo/guestInfo.c, lib/include/wiper.h, lib/wiper/*, + toolbox/toolboxcmd-shrink.c, toolbox/toolboxShrink.c: refactor the wiper + structures so that they behave the same on Win32 and other platforms, and + also reuse data structures already in use by other parts of the code. This + fixes an "use after free" issue that toolbox-cmd had on Win32. + + * lib/guestInfo/guestInfo.c, lib/guestInfo/guestInfoInt.h, + lib/guestInfo/guestInfoPosix.c, lib/guestRpc/nicinfo.x, + lib/include/guestInfo.h, lib/include/netutil.h, lib/include/slashProc.h, + lib/netutil/netUtilLinux.c, lib/slashProc/*, + services/plugins/guestInfo/guestInfoServer.c: add support for sending more + network-related information to the host, such as routing tables and name + servers. + + * lib/hgfsBd/hgfsBd.c: don't log RPC errors when HGFS is disabled. + + * lib/hgfsHelper/*, lib/include/hgfsHelper.h, lib/vixTools/vixTools.c: new + library with functions to query information about HGFS; expose some HGFS + properties through VIX. + + * lib/hgfsServer/*, lib/hgfsServerPolicyGuest/hgfsServerPolicyGuest.c, + lib/include/hgfsServerPolicy.h: fix checking of whether an object belongs + to a particular share; this was causing issues with invalid information + being returned in certain cases. + + * lib/hgfsServer/*, lib/include/hgfsProto.h: changes to support new VIX API + calls (mostly affecting Win32 only). + + * lib/include/guestCaps.h, lib/include/unityCommon.h: add boilerplate for new + RPCs for setting windows as sticky / non-sticky (not yet implemented). + + * lib/include/hgfsProto.h: new definitions for the next version of the HGFS + protocol. + + * lib/include/xdrutil.h: make XDRUTIL_ARRAYAPPEND() more type-safe when using + GCC. + + * lib/misc/codesetOld.c: fix some issues with UTF16 -> UTF8 conversion. + + * lib/rpcChannel/rpcChannel.c, libvmtools/signalSource.c, + libvmtools/vmtools.c, libvmtools/vmtoolsConfig.c: g_assert -> ASSERT. + + * lib/unityWindowTracker/unityWindowTracker.c: fix issue with z-ordering of + modal dialogs. + + * libvmtools/vmtoolsConfig.c: fix some old config translation issues. + + * modules/freebsd/shared/*, modules/freebsd/vmblock/*: make vmblock work on + FreeBSD 8. + + * modules/freebsd/vmmemctl/*, modules/linux/vmmemctl/*, + modules/solaris/vmmemctl/*, : refactoring and code changes to support the + driver on Mac OS X. + + * modules/linux/vmblock/*, modules/linux/vmci/*, modules/linux/vsock/linux/*: + remove compatibility code for older kernels. + + * modules/linux/vmhgfs/*: fix memory leak in HgfsAccessInt(). + + * modules/linux/vmxnet3/*: fix kunmap usage in vmxnet3_shm, and reset the + shared pages when the char device is closed. + + * modules/linux/vsock/linux/af_vsock.{c,h}, modules/linux/vsock/linux/util.c: + add vsock protocol negotiation for notifyOn ops. This allows the driver to + negotiate with the remove end which version of the notification protocol to + use. + + * modules/linux/vsock/linux/notify.c, modules/linux/vsock/linux/notify.h, + modules/linux/vsock/linux/notifyQState.c, + modules/linux/vsock/linux/vsockPacket.h: add pktOn protocol. This new + protocol improves performance by detecting changes in the queue state + instead of sending WAITING_READ and WAITING_WRITE packets. + + * services/plugins/hgfsServer/hgfsPlugin.c, + services/plugins/resolutionSet/resolutionSet.c, + services/vmtoolsd/mainLoop.c, services/vmtoolsd/pluginMgr.c, + services/vmtoolsd/toolsRpc.c: load plugins even when an RPC channel cannot + be instantiated (i.e., when running outside of a virtual machine); this + allows plugins to perform actions (at load time) also when running outside + virtual machines (e.g., to undo some configuration done when the OS was run + in a VM). + + * services/vmtoolsd/mainLoop.c, services/vmtoolsd/mainPosix.c, + services/vmtoolsd/toolsCoreInt.h: handle SIGHUP differently; instead of + stopping the service, just re-load the config data. This should make it + easier to integrate the tools service with other tools such as logrotate. + + * toolbox/toolbox-cmd.c, toolbox/toolboxcmd-stat.c: remove memory info query, + which didn't really return useful information. + + * vmware-user/copyPasteUI.cpp: if the clipboard/primary with most recent + timestamp has no data on it, try the other before giving up during + copy/paste. + 2009-07-22 Marcelo Vanzin * Resync with internal trunk (2009.07.17) diff --git a/open-vm-tools/NEWS b/open-vm-tools/NEWS index d90f591ee..96ffef145 100644 --- a/open-vm-tools/NEWS +++ b/open-vm-tools/NEWS @@ -1,3 +1,14 @@ +open-vm-tools 2009.08.24 changes: + * Remove support for Linux kernels < 2.6.9. + + * The vsock now implements a new notification protocol that has better + performance than the previous. + + * New infrastructure for sending more network config-related information + about the virtual machine to the host. + + * Other bug fixes and minor improvements to the code. + open-vm-tools 2009.07.22 changes: * Better support for dkms by means of a script to help create a dkms tree. diff --git a/open-vm-tools/configure.ac b/open-vm-tools/configure.ac index 720b8b3fd..7eb54c9c2 100644 --- a/open-vm-tools/configure.ac +++ b/open-vm-tools/configure.ac @@ -35,10 +35,10 @@ ### Initialization ### -TOOLS_VERSION="2009.07.22" +TOOLS_VERSION="2009.08.24" AC_INIT( [open-vm-tools], - [2009.07.22], + [2009.08.24], [open-vm-tools-devel@lists.sourceforge.net]) # In order to make this configure script auto-detect situations where @@ -138,6 +138,9 @@ osVersion="`getOsVersion`" if test "$with_kernel_modules" = "yes"; then case "$os" in linux) + if test "$osVersion" -lt 206009; then + AC_MSG_ERROR([Kernels prior to 2.6.9 are not supported in this release of open-vm-tools. Configure using --without-kernel-modules to suppress building kernel drivers.]) + fi if test ! -d "$LINUXDIR/kernel/"; then AC_MSG_ERROR([$LINUXDIR/kernel does not exist]) fi @@ -928,22 +931,10 @@ if test "$os" = "linux"; then CPPFLAGS="$CPPFLAGS -D_BSD_SOURCE" CPPFLAGS="$CPPFLAGS -D_SVID_SOURCE" - if test "$osVersion" -ge 202000; then - MODULES="$MODULES vmmemctl vmxnet" - fi - if test "$osVersion" -ge 204000; then - MODULES="$MODULES vmblock vmci vmhgfs vsock" - buildHgfsmounter=yes - fi - if test "$osVersion" -ge 206000; then - MODULES="$MODULES vmxnet3" - fi - if test "$osVersion" -ge 206006; then - MODULES="$MODULES vmsync" - fi - if test "$osVersion" -ge 206008; then - MODULES="$MODULES pvscsi" - fi + MODULES="$MODULES vmmemctl vmsync vmci vsock" + MODULES="$MODULES vmxnet vmxnet3 pvscsi" + MODULES="$MODULES vmblock vmhgfs" + buildHgfsmounter=yes fi if test "$os" = "freebsd"; then @@ -1172,6 +1163,7 @@ AC_CONFIG_FILES([ \ lib/guestRpc/Makefile \ lib/hgfs/Makefile \ lib/hgfsBd/Makefile \ + lib/hgfsHelper/Makefile \ lib/hgfsServer/Makefile \ lib/hgfsServerManagerGuest/Makefile \ lib/hgfsServerPolicyGuest/Makefile \ @@ -1192,6 +1184,7 @@ AC_CONFIG_FILES([ \ lib/rpcOut/Makefile \ lib/rpcVmx/Makefile \ lib/SLPv2Parser/Makefile \ + lib/slashProc/Makefile \ lib/string/Makefile \ lib/stubs/Makefile \ lib/sync/Makefile \ @@ -1234,6 +1227,7 @@ AC_CONFIG_FILES([ \ tests/vmrpcdbg/Makefile \ tests/testDebug/Makefile \ tests/testPlugin/Makefile \ + tests/testVmblock/Makefile \ docs/Makefile \ docs/api/Makefile \ scripts/Makefile \ diff --git a/open-vm-tools/docs/api/services/utils.txt b/open-vm-tools/docs/api/services/utils.txt index e92743a7f..dbb710f26 100644 --- a/open-vm-tools/docs/api/services/utils.txt +++ b/open-vm-tools/docs/api/services/utils.txt @@ -47,10 +47,11 @@ for each domain are: - Valid values: error, critical, warning, message, info, debug, none - This value is required when configuring a domain. - handler: the handler to use when logging. - - Valid values: std, outputdebugstring (Win32-only), file + - Valid values: std, outputdebugstring (Win32-only), file, file+ + (same as "file", but appends to existing log file). - Default: "std" on Unix, "outputdebugstring" on Windows. - data: optional configuration data for the handler. - - Required for the "file" handler (path to log file). + - Required for the "file" handlers (path to log file). Logging configuration should be under the "[logging]" group in the application's configuration file. diff --git a/open-vm-tools/lib/Makefile.am b/open-vm-tools/lib/Makefile.am index c83035ff0..7214393eb 100644 --- a/open-vm-tools/lib/Makefile.am +++ b/open-vm-tools/lib/Makefile.am @@ -42,6 +42,7 @@ SUBDIRS += guestApp SUBDIRS += guestInfo SUBDIRS += hgfs SUBDIRS += hgfsBd +SUBDIRS += hgfsHelper SUBDIRS += hgfsServer SUBDIRS += hgfsServerManagerGuest SUBDIRS += hgfsServerPolicyGuest @@ -67,6 +68,9 @@ SUBDIRS += rpcChannel SUBDIRS += rpcIn SUBDIRS += rpcOut SUBDIRS += rpcVmx +if LINUX + SUBDIRS += slashProc +endif SUBDIRS += SLPv2Parser SUBDIRS += string SUBDIRS += stubs diff --git a/open-vm-tools/lib/appUtil/appUtil.c b/open-vm-tools/lib/appUtil/appUtil.c index 99bd92706..a6c149bb6 100644 --- a/open-vm-tools/lib/appUtil/appUtil.c +++ b/open-vm-tools/lib/appUtil/appUtil.c @@ -38,7 +38,7 @@ * AppUtil_SendGuestCaps -- * * Send a list of guest capabilities to the host. - * + * * Results: * None. * diff --git a/open-vm-tools/lib/appUtil/appUtilX11.c b/open-vm-tools/lib/appUtil/appUtilX11.c index b37b22eaf..5ac358e69 100644 --- a/open-vm-tools/lib/appUtil/appUtilX11.c +++ b/open-vm-tools/lib/appUtil/appUtilX11.c @@ -36,6 +36,7 @@ #error "Gtk 2.0 is required" #endif +#include #include #include #include diff --git a/open-vm-tools/lib/dnd/dndLinux.c b/open-vm-tools/lib/dnd/dndLinux.c index 8e37a4a9c..94cb81e7d 100644 --- a/open-vm-tools/lib/dnd/dndLinux.c +++ b/open-vm-tools/lib/dnd/dndLinux.c @@ -40,7 +40,7 @@ #include "escape.h" #include "su.h" #if defined(linux) || defined(sun) || defined(__FreeBSD__) -#include "vmblock.h" +#include "vmblock_user.h" #include "mntinfo.h" #endif @@ -261,43 +261,6 @@ DnD_UriListGetNextFile(char const *uriList, // IN : text/uri-list string /* We need to make this suck less. */ #if defined(linux) || defined(sun) || defined(__FreeBSD__) -#if defined(linux) - -static INLINE int -VMBLOCK_CONTROL(int fd, int op, const char *path) -{ - return write(fd, path, op); -} - -#elif defined(__FreeBSD__) - -static INLINE int -VMBLOCK_CONTROL(int fd, int cmd, const char *path) -{ - char tpath[MAXPATHLEN]; - - if (path != NULL) { - /* - * FreeBSD's ioctl data parameters must be of fixed size. Guarantee a safe - * buffer of size MAXPATHLEN by copying the user's string to one of our own. - */ - strlcpy(tpath, path, MAXPATHLEN); - } - - return ioctl(fd, cmd, tpath); -} - -#elif defined(sun) - -static INLINE int -VMBLOCK_CONTROL(int fd, int cmd, const char *path) -{ - return ioctl(fd, cmd, path); -} - -#endif - - /* *---------------------------------------------------------------------------- * @@ -390,66 +353,6 @@ DnD_CheckBlockLegacy(int blockFd) // IN } -/* - * DnD_VmblockFuseControl -- - * - * Controlling function for FUSE-based blocker implementation. - * Passes requests to block and unblock file access to fuse module. - * - * Results: - * 0 on success, -1 on failure. - * - * Notes: - * None. - * - */ - -static ssize_t -DnD_VmblockFuseControl(int fd, // IN - char op, // IN - const char *path) // IN -{ - /* - * buffer needs room for an operation character and a string with max length - * PATH_MAX - 1. - */ - - char buffer[PATH_MAX]; - size_t pathLength; - - pathLength = strlen(path); - if (pathLength >= PATH_MAX) { - errno = ENAMETOOLONG; - return -1; - } - - buffer[0] = op; - memcpy(buffer + 1, path, pathLength); - - /* - * The lseek is only to prevent the file pointer from overflowing; - * vmblock-fuse ignores the file pointer / offset. Overflowing the file - * pointer causes write to fail: - * http://article.gmane.org/gmane.comp.file-systems.fuse.devel/6648 - * There's also a race condition here where many threads all calling - * VMBLOCK_CONTROL at the same time could have all their seeks executed one - * after the other, followed by all the writes. Again, it's not a problem - * unless the file pointer overflows which is very unlikely with 32 bit - * offsets and practically impossible with 64 bit offsets. - */ - - if (lseek(fd, 0, SEEK_SET) < 0) { - return -1; - } - - if (write(fd, buffer, pathLength + 1) < 0) { - return -1; - } - - return 0; -} - - /* *---------------------------------------------------------------------------- * @@ -473,8 +376,8 @@ DnD_AddBlockFuse(int blockFd, // IN { ASSERT(blockFd >= 0); - if (DnD_VmblockFuseControl(blockFd, VMBLOCK_FUSE_ADD_FILEBLOCK, - blockPath) != 0) { + if (VMBLOCK_CONTROL_FUSE(blockFd, VMBLOCK_FUSE_ADD_FILEBLOCK, + blockPath) != 0) { LOG(1, ("%s: Cannot add block on %s (%s)\n", __func__, blockPath, strerror(errno))); return FALSE; @@ -505,8 +408,8 @@ DnD_RemoveBlockFuse(int blockFd, // IN const char *blockedPath) // IN { if (blockFd >= 0) { - if (DnD_VmblockFuseControl(blockFd, VMBLOCK_FUSE_DEL_FILEBLOCK, - blockedPath) != 0) { + if (VMBLOCK_CONTROL_FUSE(blockFd, VMBLOCK_FUSE_DEL_FILEBLOCK, + blockedPath) != 0) { Log("%s: Cannot delete block on %s (%s)\n", __func__, blockedPath, strerror(errno)); return FALSE; diff --git a/open-vm-tools/lib/file/file.c b/open-vm-tools/lib/file/file.c index 10833932e..9f918e491 100644 --- a/open-vm-tools/lib/file/file.c +++ b/open-vm-tools/lib/file/file.c @@ -31,6 +31,7 @@ #if defined(_WIN32) #include #define S_IXUSR 0100 +#define S_IWUSR 0200 #else #include #endif @@ -1942,7 +1943,17 @@ File_DeleteDirectoryTree(ConstUnicode pathName) // IN: directory to delete } else { /* is file, delete */ if (File_Unlink(curPath) == -1) { +#if defined(_WIN32) + if (File_SetFilePermissions(curPath, S_IWUSR)) { + if (File_Unlink(curPath) == -1) { + sawFileError = TRUE; + } + } else { + sawFileError = TRUE; + } +#else sawFileError = TRUE; +#endif } } diff --git a/open-vm-tools/lib/file/fileIO.c b/open-vm-tools/lib/file/fileIO.c index b21531a45..9f7380a15 100644 --- a/open-vm-tools/lib/file/fileIO.c +++ b/open-vm-tools/lib/file/fileIO.c @@ -273,13 +273,20 @@ FileIO_Lock(FileIODescriptor *file, // IN/OUT: /* Return a serious failure status if the locking code did */ switch (err) { - case 0: // file is currently locked + case 0: // File is currently locked + case EROFS: // Attempt to lock for write on RO FS ret = FILEIO_LOCK_FAILED; break; - case ENAMETOOLONG: // path is too long + case ENAMETOOLONG: // Path is too long ret = FILEIO_FILE_NAME_TOO_LONG; break; - default: // some sort of locking error + case ENOENT: // No such file or directory + ret = FILEIO_FILE_NOT_FOUND; + break; + case EACCES: // Permissions issues + ret = FILEIO_NO_PERMISSION; + break; + default: // Some sort of locking error ret = FILEIO_ERROR; } } diff --git a/open-vm-tools/lib/file/fileIOPosix.c b/open-vm-tools/lib/file/fileIOPosix.c index d07a8c5b8..a8634eddf 100644 --- a/open-vm-tools/lib/file/fileIOPosix.c +++ b/open-vm-tools/lib/file/fileIOPosix.c @@ -91,26 +91,30 @@ #include "unicodeOperations.h" #include "memaligned.h" -#if defined(__APPLE__) +#if defined(__APPLE__) || defined(__linux__) #include "hostinfo.h" +#endif + +#if defined(__APPLE__) +#include #define XATTR_BACKUP_REENABLED "com.vmware.backupReenabled" #endif -/* +/* * fallocate() is only supported since the glibc-2.8 and - * linux kernel-2.6.23.Presently the glibc in our toolchain is 2.3 + * linux kernel-2.6.23. Presently the glibc in our toolchain is 2.3. */ #ifdef __linux__ - #ifndef SYS_fallocate + #ifndef SYS_fallocate #ifdef __i386__ - #define SYS_fallocate 324 - #elif __x86_64__ - #define SYS_fallocate 285 + #define SYS_fallocate 324 + #elif __x86_64__ + #define SYS_fallocate 285 #endif #endif - #ifndef FALLOC_FL_KEEP_SIZE - #define FALLOC_FL_KEEP_SIZE 1 - #endif + #ifndef FALLOC_FL_KEEP_SIZE + #define FALLOC_FL_KEEP_SIZE 1 + #endif #endif static const unsigned int FileIO_SeekOrigins[] = { @@ -136,6 +140,7 @@ typedef struct FilePosixOptions { Bool enabled; int countThreshold; int sizeThreshold; + int aioNumThreads; } FilePosixOptions; #if defined(__APPLE__) @@ -235,6 +240,8 @@ FileIO_OptionalSafeInitialize(void) Config_GetLong(5, "filePosix.coalesce.count"); filePosixOptions.sizeThreshold = Config_GetLong(16*1024, "filePosix.coalesce.size"); + filePosixOptions.aioNumThreads = + Config_GetLong(0, "aiomgr.numThreads"); filePosixOptions.initialized = TRUE; } } @@ -1687,9 +1694,8 @@ FileIO_Preadv(FileIODescriptor *fd, // IN: File descriptor ssize_t retval = pread(fd->posix, buf, leftToRead, fileOffset); if (retval == -1) { - if (errno == EINTR || errno == EAGAIN) { - LOG_ONCE((LGPFX" %s got %s. Retrying\n", - __FUNCTION__, errno == EINTR ? "EINTR" : "EAGAIN")); + if (errno == EINTR) { + LOG_ONCE((LGPFX" %s got EINTR. Retrying\n", __FUNCTION__)); NOT_TESTED_ONCE(); continue; } @@ -1787,9 +1793,8 @@ FileIO_Pwritev(FileIODescriptor *fd, // IN: File descriptor ssize_t retval = pwrite(fd->posix, buf, leftToWrite, fileOffset); if (retval == -1) { - if (errno == EINTR || errno == EAGAIN) { - LOG_ONCE((LGPFX" %s got %s. Retrying\n", - __FUNCTION__, errno == EINTR ? "EINTR" : "EAGAIN")); + if (errno == EINTR) { + LOG_ONCE((LGPFX" %s got EINTR. Retrying\n", __FUNCTION__)); NOT_TESTED_ONCE(); continue; } @@ -1878,7 +1883,7 @@ FileIO_GetAllocSize(const FileIODescriptor *fd) // IN ASSERT(fd); #if __linux__ && defined(N_PLAT_NLM) - /* Netware doesn't have st_blocks. Just fall back to GetSize. */ + /* Netware doesn't have st_blocks. Just fall back to GetSize. */ return FileIO_GetSize(fd); #else /* @@ -1902,7 +1907,7 @@ FileIO_GetAllocSize(const FileIODescriptor *fd) // IN * TRUE on success. Sets errno on failure. * * Side effects: - * None + * None. * *---------------------------------------------------------------------- */ @@ -1923,7 +1928,7 @@ FileIO_SetAllocSize(const FileIODescriptor *fd, // IN if (curSize > size) { errno = EINVAL; return FALSE; - } + } preallocLen = size - curSize; #ifdef __APPLE__ @@ -1935,8 +1940,17 @@ FileIO_SetAllocSize(const FileIODescriptor *fd, // IN return fcntl(fd->posix, F_PREALLOCATE, &prealloc) != -1; #elif __linux__ - return syscall(SYS_fallocate, fd->posix, FALLOC_FL_KEEP_SIZE, - curSize, preallocLen) == 0; + { + int ret; + + ret = syscall(SYS_fallocate, fd->posix, FALLOC_FL_KEEP_SIZE, + curSize, preallocLen); + if (ret == 0) { + return TRUE; + } + errno = ret; + return FALSE; + } #endif #else @@ -2416,6 +2430,174 @@ exit: return result; } + +/* + *---------------------------------------------------------------------- + * + * HostSupportsPrealloc -- + * + * Returns TRUE if the host OS is new enough to support F_PREALLOCATE + * without data loss bugs. On OSX, this has been verified fixed + * on 10.6 build with kern.osreleasae 10.0.0d6. + * + * Results: + * TRUE if the current host OS is new enough. + * FALSE if it is not or we can't tell because of an error. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Bool +HostSupportsPrealloc(void) +{ + char curRel[32]; + char type; + unsigned static const int req[] = { 10, 0, 0, 6 }; + unsigned int cur[4], i; + int num; + size_t len = sizeof(curRel); + Bool ret = FALSE; + + if (sysctlbyname("kern.osrelease", (void *) &curRel, &len, NULL, 0) == -1) { + goto exit; + } + + curRel[31] = '\0'; + Log("Current OS Release is %s\n", curRel); + + /* + * Apple's osversion is in the format X.Y.Z which maps to the public + * OSX version 10.X-4.Y, and Z is incremented for each publicly + * released build. The Z part is of the form AB, where a and + * B are version numbers and is either d (devel), a (alpha), + * b (beta), rc, or fc. If the B is missing, then its a GA build. + * + * Since we're checking for 10.0.0d6, we can just say anything without + * a type or with a type other than d is higher. For d, we compare + * the last number. + */ + + num = sscanf(curRel, "%u.%u.%u%c%u", &cur[0], &cur[1], &cur[2], &type, + &cur[3]); + if (num < 3) { + goto exit; + } + + for (i = 0; i < 3; i++) { + if (req[i] > cur[i]) { + goto exit; + } else if (req[i] < cur[i]) { + ret = TRUE; + goto exit; + } + } + if (num == 5 && type == 'd') { + ret = req[3] <= cur[3]; + goto exit; + } + /* + * If we get a type with no letter (num == 4), thats odd. + * Consider it mal-formatted and fail. + */ + ret = num != 4; + +exit: + if (!ret && filePosixOptions.initialized && + filePosixOptions.aioNumThreads == 1) { + ret =TRUE; + } + return ret; +} + +#else + +/* + *---------------------------------------------------------------------- + * + * HostSupportsPrealloc -- + * + * fallocate() is supported for ext4 and xfs since 2.6.23 kernels + * + * Results: + * TRUE if the current host is linux and kernel is >= 2.6.23. + * FALSE if it is not . + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static Bool +HostSupportsPrealloc(void) +{ +#if (defined(__linux__ ) && !defined(VMX86_SERVER)) + if (Hostinfo_OSVersion(0) >=2 && Hostinfo_OSVersion(1) >=6 && + Hostinfo_OSVersion(2) >=23) { + return TRUE; + } +#endif + return FALSE; +} + #endif +/* + *---------------------------------------------------------------------------- + * + * FileIO_SupportsPrealloc -- + * + * Checks if the HostOS/filesystem supports preallocation. + * + * Results: + * TRUE if supported by the Host OS/filesystem. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +Bool +FileIO_SupportsPrealloc(const char *pathName, // IN + Bool fsCheck) // IN +{ + Bool ret = TRUE; + + if (!HostSupportsPrealloc()) { + return FALSE; + } + + if (!fsCheck) { + return ret; + } + +#if (defined( __linux__) && !defined(VMX86_SERVER)) + { + struct statfs statBuf; + Unicode fullPath; + + ret = FALSE; + if (!pathName) { + return ret; + } + + fullPath = File_FullPath(pathName); + if (!fullPath) { + return ret; + } + + if (Posix_Statfs(fullPath, &statBuf) == 0 && + statBuf.f_type == EXT4_SUPER_MAGIC) { + ret = TRUE; + } + Unicode_Free(fullPath); + } +#endif + return ret; +} + diff --git a/open-vm-tools/lib/file/filePosix.c b/open-vm-tools/lib/file/filePosix.c index 2912f888e..f5d955bc1 100644 --- a/open-vm-tools/lib/file/filePosix.c +++ b/open-vm-tools/lib/file/filePosix.c @@ -1005,26 +1005,69 @@ File_GetFreeSpace(ConstUnicode pathName, // IN: File name if (statfsbuf.f_type == VMFS_MAGIC_NUMBER) { int fd; FS_FreeSpaceArgs args = { 0 }; - Unicode directory = NULL; + Unicode specialPath = NULL; + + /* + * If the file exists and can be opened we're all set. If the file + * doesn't exist we can use the parent directory for the ioctl. + * However, if the file exists and can't be opened (e.g. permissions + * issues) a correct answer can only be returned if the target isn't a + * directory. If the target is a directory its parent may be a mount + * point - leading across a mount point to a different file system. + * PR 412387 + */ - File_SplitName(fullPath, NULL, &directory, NULL); - /* Must use an ioctl() to get free space for a VMFS file. */ ret = -1; - fd = Posix_Open(directory, O_RDONLY, 0); + + fd = Posix_Open(fullPath, O_RDONLY, 0); + + if (fd == -1) { + switch (errno) { + case EPERM: + case EACCES: + { + int err = errno; + struct stat statbuf; + + if (Posix_Stat(fullPath, &statbuf) == -1) { + errno = err; + break; + } + + if ((statbuf.st_mode & S_IFMT) == S_IFDIR) { + Warning(LGPFX" %s: directory (%s) present but inaccessible\n", + __func__, UTF8(fullPath)); + errno = err; + break; + } + } + /* FALLTHROUGH */ + + case ENOENT: + default: + File_SplitName(fullPath, NULL, &specialPath, NULL); + + fd = Posix_Open(specialPath, O_RDONLY, 0); + } + } + if (fd == -1) { Warning(LGPFX" %s: open of %s failed with: %s\n", __func__, - UTF8(directory), Msg_ErrString()); + (specialPath == NULL) ? UTF8(fullPath) : UTF8(specialPath), + Msg_ErrString()); } else { if (ioctl(fd, IOCTLCMD_VMFS_GET_FREE_SPACE, &args) == -1) { Warning(LGPFX" %s: ioctl on %s failed with: %s\n", __func__, - UTF8(fullPath), Msg_ErrString()); + (specialPath == NULL) ? UTF8(fullPath) : UTF8(specialPath), + Msg_ErrString()); } else { ret = args.bytesFree; } + close(fd); } - Unicode_Free(directory); + Unicode_Free(specialPath); } #endif @@ -2818,36 +2861,3 @@ File_IsCharDevice(ConstUnicode pathName) // IN: return (FileAttributes(pathName, &fileData) == 0) && (fileData.fileType == FILE_TYPE_CHARDEVICE); } - - -/* - *---------------------------------------------------------------------------- - * - * File_SupportsPrealloc -- - * - * - * Results: - * TRUE if APPLE or file system type is ext2/ext3/ext4 - * FALSE if not supported by default in auto mode - * - * Side effects: - * None - * - *---------------------------------------------------------------------------- - */ - -Bool -File_SupportsPrealloc(const char *file) -{ - -#if (defined( __linux__) && !defined(VMX86_SERVER)) - struct statfs statBuf; - if (FileGetStats(file, FALSE, &statBuf) && - statBuf.f_type == EXT4_SUPER_MAGIC) { - return TRUE; - } -#elif APPLE - return TRUE -#endif - return FALSE; -} diff --git a/open-vm-tools/lib/foundryMsg/foundryMsg.c b/open-vm-tools/lib/foundryMsg/foundryMsg.c index 6dc351976..53bd7373a 100644 --- a/open-vm-tools/lib/foundryMsg/foundryMsg.c +++ b/open-vm-tools/lib/foundryMsg/foundryMsg.c @@ -430,6 +430,11 @@ static const VixCommandInfo vixCommandInfoTable[] = { VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_REMOVE_BULK_SNAPSHOT, VIX_COMMAND_CATEGORY_PRIVILEGED), + VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_COPY_FILE_FROM_READER_TO_GUEST, + VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), + + VIX_DEFINE_COMMAND_INFO(VIX_COMMAND_GENERATE_NONCE, + VIX_COMMAND_CATEGORY_ALWAYS_ALLOWED), }; @@ -760,6 +765,15 @@ VixMsg_ValidateRequestMsg(const void *vMsg, // IN return VIX_E_INVALID_MESSAGE_HEADER; } + if ((VIX_REQUESTMSG_INCLUDES_AUTH_DATA_V1 & message->requestFlags) && + (message->commonHeader.totalMessageLength < + (uint64)message->commonHeader.headerLength + + message->commonHeader.bodyLength + + message->commonHeader.credentialLength + + sizeof (VixMsgAuthDataV1))) { + return VIX_E_INVALID_MESSAGE_HEADER; + } + return VIX_OK; } // VixMsg_ValidateRequestMsg diff --git a/open-vm-tools/lib/ghIntegration/ghIntegrationX11.c b/open-vm-tools/lib/ghIntegration/ghIntegrationX11.c index 312d42d37..7408b82b7 100644 --- a/open-vm-tools/lib/ghIntegration/ghIntegrationX11.c +++ b/open-vm-tools/lib/ghIntegration/ghIntegrationX11.c @@ -62,8 +62,8 @@ #include "imageUtil.h" #include "strutil.h" #include -#include #include "vm_atomic.h" +#include "mntinfo.h" #include "ghIntegration.h" #include "ghIntegrationInt.h" #include "guest_msg_def.h" diff --git a/open-vm-tools/lib/guestInfo/Makefile.am b/open-vm-tools/lib/guestInfo/Makefile.am index a276f8176..cf06d4f44 100644 --- a/open-vm-tools/lib/guestInfo/Makefile.am +++ b/open-vm-tools/lib/guestInfo/Makefile.am @@ -21,5 +21,8 @@ libGuestInfo_la_SOURCES = libGuestInfo_la_SOURCES += guestInfo.c libGuestInfo_la_SOURCES += guestInfoPosix.c +libGuestInfo_la_CPPFLAGS = +libGuestInfo_la_CPPFLAGS += @GLIB2_CPPFLAGS@ + AM_CFLAGS = $(DNET_CPPFLAGS) diff --git a/open-vm-tools/lib/guestInfo/guestInfo.c b/open-vm-tools/lib/guestInfo/guestInfo.c index 7d1c16277..6b69ef2aa 100644 --- a/open-vm-tools/lib/guestInfo/guestInfo.c +++ b/open-vm-tools/lib/guestInfo/guestInfo.c @@ -16,46 +16,65 @@ * *********************************************************/ -/* - * guestInfo.c --- +/** + * @file guestInfo.c * - * Provides interface to information about the guest, such as hostname, - * NIC/IP address information, etc. + * Library backing parts of the vm.GuestInfo VIM APIs. */ #include #include +#if defined _WIN32 +# include +#endif + #include "vm_assert.h" #include "debug.h" #include "guestInfoInt.h" #include "str.h" +#include "util.h" #include "wiper.h" #include "xdrutil.h" +#include "netutil.h" + + +/** + * Helper to initialize an opaque struct member. + * + * @todo Move to xdrutil.h? Sticking point is dependency on Util_SafeMalloc. + */ +#define XDRUTIL_SAFESETOPAQUE(ptr, type, src, size) \ + do { \ + (ptr)->type##_len = (size); \ + (ptr)->type##_val = Util_SafeMalloc((size)); \ + memcpy((ptr)->type##_val, (src), (size)); \ + } while (0) /* - * Global functions + * Global functions. */ - + /* - *----------------------------------------------------------------------------- + ****************************************************************************** + * GuestInfo_GetAvailableDiskSpace -- */ /** * - * GuestInfo_GetAvailableDiskSpace -- + * @brief Given a mount point, return the amount of free space on that volume. * - * Get the amount of disk space available on the volume the FCP (file copy/ - * paste) staging area is in. DnD and FCP use same staging area in guest. - * But it is only called in host->guest FCP case. DnD checks guest available - * disk space in host side (UI). + * Get the amount of disk space available on the volume the FCP (file copy/ + * paste) staging area is in. DnD and FCP use same staging area in guest. + * But it is only called in host->guest FCP case. DnD checks guest available + * disk space in host side (UI). * - * Results: - * Available disk space size if succeed, otherwise 0. + * @param[in] pathName Mount point to examine. * - * Side effects: - * None. + * @todo This doesn't belong in lib/guestInfo. * - *----------------------------------------------------------------------------- + * @return Bytes free on success, 0 on failure. + * + ****************************************************************************** */ uint64 @@ -81,256 +100,402 @@ GuestInfo_GetAvailableDiskSpace(char *pathName) } - /* - *----------------------------------------------------------------------------- + ****************************************************************************** + * GuestInfo_GetFqdn -- */ /** * - * GuestInfo_GetFqdn -- + * @brief Returns the guest's hostname (aka fully qualified domain name, FQDN). * - * Returns the guest's hostname. + * @param[in] outBufLen Size of outBuf. + * @param[out] outBuf Output buffer. * - * Results: - * Returns TRUE on success, FALSE on failure. - * Returns the guest's fully qualified domain name in fqdn. + * @retval TRUE Success. Hostname written to @a outBuf. + * @retval FALSE Failure. * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- + ****************************************************************************** */ Bool -GuestInfo_GetFqdn(int outBufLen, // IN: sizeof fqdn - char fqdn[]) // OUT: buffer to store hostname +GuestInfo_GetFqdn(int outBufLen, // IN + char fqdn[]) // OUT { return GuestInfoGetFqdn(outBufLen, fqdn); } /* - *----------------------------------------------------------------------------- - * - * GuestInfo_GetNicInfo -- + ****************************************************************************** + * GuestInfo_GetNicInfo -- */ /** * - * Returns the guest's hostname. + * @brief Returns guest networking configuration (and some runtime state). * - * Results: - * Return MAC addresses of all the NICs in the guest and their - * corresponding IP addresses. + * @param[out] nicInfo Will point to a newly allocated NicInfo. * - * Returns TRUE on success and FALSE on failure. - * Return MAC addresses of all NICs and their corresponding IPs. + * @note + * Caller is responsible for freeing @a nicInfo with GuestInfo_FreeNicInfo. * - * Side effects: - * Memory is allocated for each NIC, as well as IP addresses of all NICs - * on successful return. + * @retval TRUE Success. @a nicInfo now points to a populated NicInfoV3. + * @retval FALSE Failure. * - *----------------------------------------------------------------------------- + ****************************************************************************** */ Bool -GuestInfo_GetNicInfo(GuestNicList *nicInfo) // OUT: storage for NIC information +GuestInfo_GetNicInfo(NicInfoV3 **nicInfo) // OUT { - return GuestInfoGetNicInfo(nicInfo); + Bool retval = FALSE; + + *nicInfo = Util_SafeCalloc(1, sizeof (struct NicInfoV3)); + + retval = GuestInfoGetNicInfo(*nicInfo); + if (!retval) { + free(*nicInfo); + *nicInfo = NULL; + } + + return retval; } /* - *---------------------------------------------------------------------- + ****************************************************************************** + * GuestInfo_FreeNicInfo -- */ /** * - * GuestInfo_GetDiskInfo -- + * @brief Frees a NicInfoV3 structure and all memory it points to. * - * Get disk information. + * @param[in] nicInfo Pointer to NicInfoV3 container. * - * Results: - * TRUE if successful, FALSE otherwise. + * @sa GuestInfo_GetNicInfo * - * Side effects: - * Allocates memory for di->partitionList. + ****************************************************************************** + */ + +void +GuestInfo_FreeNicInfo(NicInfoV3 *nicInfo) // IN +{ + if (nicInfo != NULL) { + VMX_XDR_FREE(xdr_NicInfoV3, nicInfo); + free(nicInfo); + } +} + + +/* + ****************************************************************************** + * GuestInfo_GetDiskInfo -- */ /** * - *---------------------------------------------------------------------- + * @brief Get disk information. + * + * @param[in,out] di DiskInfo container. + * + * @note + * Allocates memory for di->partitionList. + * + * @retval TRUE Success. + * @retval FALSE Failure. + * + ****************************************************************************** */ Bool GuestInfo_GetDiskInfo(PGuestDiskInfo di) // IN/OUT { - return GuestInfoGetDiskInfo(di); + WiperPartition_List pl; + DblLnkLst_Links *curr; + unsigned int partCount = 0; + uint64 freeBytes = 0; + uint64 totalBytes = 0; + unsigned int partNameSize = 0; + Bool success = FALSE; + + ASSERT(di); + partNameSize = sizeof (di->partitionList)[0].name; + di->numEntries = 0; + di->partitionList = NULL; + + /* Get partition list. */ + if (!WiperPartition_Open(&pl)) { + Debug("GetDiskInfo: ERROR: could not get partition list\n"); + return FALSE; + } + + DblLnkLst_ForEach(curr, &pl.link) { + WiperPartition *part = DblLnkLst_Container(curr, WiperPartition, link); + + if (part->type != PARTITION_UNSUPPORTED) { + PPartitionEntry newPartitionList; + PPartitionEntry partEntry; + unsigned char *error; + + error = WiperSinglePartition_GetSpace(part, &freeBytes, &totalBytes); + if (strlen(error)) { + Debug("GetDiskInfo: ERROR: could not get space for partition %s: %s\n", + part->mountPoint, error); + goto out; + } + + if (strlen(part->mountPoint) + 1 > partNameSize) { + Debug("GetDiskInfo: ERROR: Partition name buffer too small\n"); + goto out; + } + + newPartitionList = realloc(di->partitionList, + (partCount + 1) * sizeof *di->partitionList); + if (newPartitionList == NULL) { + Debug("GetDiskInfo: ERROR: could not allocate partition list.\n"); + goto out; + } + + partEntry = &newPartitionList[partCount++]; + Str_Strcpy(partEntry->name, part->mountPoint, partNameSize); + partEntry->freeBytes = freeBytes; + partEntry->totalBytes = totalBytes; + + di->partitionList = newPartitionList; + } + } + + di->numEntries = partCount; + success = TRUE; + +out: + WiperPartition_Close(&pl); + return success; } -/** - * Add a NIC into the given list. The macAddress of the new GuestNic is - * initialized with the given address. +/* + * Private library functions. + */ + + +/* + ****************************************************************************** + * GuestInfoAddNicEntry -- */ /** + * + * @brief GuestNicV3 constructor. * * @param[in,out] nicInfo List of NICs. * @param[in] macAddress MAC address of new NIC. + * @param[in] dnsInfo Per-NIC DNS config state. + * + * @note The returned GuestNic will take ownership of @a dnsInfo. The caller + * must not free it directly. * - * @return The new NIC, or NULL on failure. + * @return Pointer to the new NIC. + * + ****************************************************************************** */ -GuestNic * -GuestInfoAddNicEntry(GuestNicList *nicInfo, // IN/OUT - const char macAddress[NICINFO_MAC_LEN]) // IN +GuestNicV3 * +GuestInfoAddNicEntry(NicInfoV3 *nicInfo, // IN/OUT + const char macAddress[NICINFO_MAC_LEN], // IN + DnsConfigInfo *dnsInfo) // IN { - GuestNic *newNic; + GuestNicV3 *newNic; newNic = XDRUTIL_ARRAYAPPEND(nicInfo, nics, 1); - if (newNic != NULL) { - Str_Strcpy(newNic->macAddress, macAddress, sizeof newNic->macAddress); - } + ASSERT_MEM_ALLOC(newNic); + + newNic->macAddress = Util_SafeStrdup(macAddress); + newNic->dnsConfigInfo = dnsInfo; return newNic; } -/** - * Add an IP address entry into the GuestNic. +/* + ****************************************************************************** + * GuestInfoAddIpAddress -- */ /** + * + * @brief Add an IP address entry into the GuestNic. * * @param[in,out] nic The NIC information. - * @param[in] ipAddr The new IP address to add. - * @param[in] af_type Interface type. + * @param[in] sockAddr The new IP address. + * @param[in] pfxLen Prefix length (use 0 if unknown). + * @param[in] origin Address's origin. (Optional.) + * @param[in] status Address's status. (Optional.) * * @return Newly allocated IP address struct, NULL on failure. + * + ****************************************************************************** */ -VmIpAddress * -GuestInfoAddIpAddress(GuestNic *nic, // IN/OUT - const char *ipAddr, // IN - const uint32 af_type) // IN +IpAddressEntry * +GuestInfoAddIpAddress(GuestNicV3 *nic, // IN/OUT + const struct sockaddr *sockAddr, // IN + InetAddressPrefixLength pfxLen, // IN + const IpAddressOrigin *origin, // IN + const IpAddressStatus *status) // IN { - VmIpAddress *ip; + IpAddressEntry *ip; + + ASSERT(sockAddr); ip = XDRUTIL_ARRAYAPPEND(nic, ips, 1); - if (ip != NULL) { - Str_Strcpy(ip->ipAddress, ipAddr, sizeof ip->ipAddress); - ip->addressFamily = af_type; + ASSERT_MEM_ALLOC(ip); + + ASSERT_ON_COMPILE(sizeof *origin == sizeof *ip->ipAddressOrigin); + ASSERT_ON_COMPILE(sizeof *status == sizeof *ip->ipAddressStatus); + + switch (sockAddr->sa_family) { + case AF_INET: + { + static const IpAddressStatus defaultStatus = IAS_PREFERRED; + + GuestInfoSockaddrToTypedIpAddress(sockAddr, &ip->ipAddressAddr); + + ip->ipAddressPrefixLength = pfxLen; + ip->ipAddressOrigin = origin ? Util_DupeThis(origin, sizeof *origin) : NULL; + ip->ipAddressStatus = status ? Util_DupeThis(status, sizeof *status) : + Util_DupeThis(&defaultStatus, sizeof defaultStatus); + } + break; + case AF_INET6: + { + static const IpAddressStatus defaultStatus = IAS_UNKNOWN; + + GuestInfoSockaddrToTypedIpAddress(sockAddr, &ip->ipAddressAddr); + + ip->ipAddressPrefixLength = pfxLen; + ip->ipAddressOrigin = origin ? Util_DupeThis(origin, sizeof *origin) : NULL; + ip->ipAddressStatus = status ? Util_DupeThis(status, sizeof *status) : + Util_DupeThis(&defaultStatus, sizeof defaultStatus); + } + break; + default: + NOT_REACHED(); } return ip; } -/** - * Add an IPv4 netmask / IPv6 prefix length to the IpAddress in ASCII form. +/* + ****************************************************************************** + * GuestInfoSockaddrToTypedIpAddress -- */ /** + * + * @brief Converts a struct sockaddr to a @c TypedIpAddress. * - * If convertToMask is true the 'n' bits subnet mask is converted - * to an ASCII string as a hexadecimal number (0xffffff00) and - * added to the IPAddressEntry. (Applies to IPv4 only.) + * @param[in] sa Source @c sockaddr. + * @param[out] typedIp Destination @c TypedIpAddress. * - * If convertToMask is false the value is added to the IPAddressEntry in - * string form - ie '24'. + * @warning Caller is responsible for making sure source is AF_INET or + * AF_INET6. * - * @param[in,out] ipAddressEntry The IP address info. - * @param[in] subnetMaskBits The mask. - * @param[in] convertToMask See above. + ****************************************************************************** */ void -GuestInfoAddSubnetMask(VmIpAddress *ipAddressEntry, // IN/OUT - const uint32 subnetMaskBits, // IN - Bool convertToMask) // IN +GuestInfoSockaddrToTypedIpAddress(const struct sockaddr *sa, // IN + TypedIpAddress *typedIp) // OUT { - int i; - uint32 subnetMask = 0; - - ASSERT(ipAddressEntry); - /* - * It's an error to set convertToMask on an IPv6 address. - */ - ASSERT(ipAddressEntry->addressFamily == INFO_IP_ADDRESS_FAMILY_IPV4 || - !convertToMask); - - if (convertToMask && (subnetMaskBits <= 32)) { - /* - * Convert the subnet mask from a number of bits (ie. '24') to - * hexadecimal notation such 0xffffff00 - */ - for (i = 0; i < subnetMaskBits; i++) { - subnetMask |= (0x80000000 >> i); - } - - // Convert the hexadecimal value to a string and add to the IpAddress Entry - Str_Sprintf(ipAddressEntry->subnetMask, - sizeof ipAddressEntry->subnetMask, - "0x%x", subnetMask); - } else { - Str_Sprintf(ipAddressEntry->subnetMask, - sizeof ipAddressEntry->subnetMask, - "%d", subnetMaskBits); + struct sockaddr_in *sin = (struct sockaddr_in *)sa; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + + switch (sa->sa_family) { + case AF_INET: + typedIp->ipAddressAddrType = IAT_IPV4; + XDRUTIL_SAFESETOPAQUE(&typedIp->ipAddressAddr, InetAddress, + &sin->sin_addr.s_addr, + sizeof sin->sin_addr.s_addr); + break; + case AF_INET6: + typedIp->ipAddressAddrType = IAT_IPV6; + XDRUTIL_SAFESETOPAQUE(&typedIp->ipAddressAddr, InetAddress, + &sin6->sin6_addr.s6_addr, + sizeof sin6->sin6_addr.s6_addr); + break; + default: + NOT_REACHED(); } - return; } -/** - * Get disk information. +#if defined linux || defined _WIN32 +/* + ****************************************************************************** + * GuestInfoGetNicInfoIfIndex -- */ /** + * + * @brief Given a local interface's index, find its corresponding location in the + * NicInfoV3 @c nics vector. + * + * @param[in] nicInfo NIC container. + * @param[in] ifIndex Device to search for. + * @param[out] nicifIndex Array offset, if found. * - * @param[out] di Where to store the disk information. + * @retval TRUE Device found. + * @retval FALSE Device not found. * - * @return TRUE if successful, FALSE otherwise. + ****************************************************************************** */ Bool -GuestInfoGetDiskInfo(PGuestDiskInfo di) +GuestInfoGetNicInfoIfIndex(NicInfoV3 *nicInfo, // IN + int ifIndex, // IN + int *nicIfIndex) // OUT { - int i = 0; - WiperPartition_List *pl = NULL; - unsigned int partCount = 0; - uint64 freeBytes = 0; - uint64 totalBytes = 0; - WiperPartition nextPartition; - unsigned int partNameSize = 0; - Bool success = FALSE; - - ASSERT(di); - partNameSize = sizeof (di->partitionList)[0].name; - di->numEntries = 0; - di->partitionList = NULL; - - /* Get partition list. */ - pl = WiperPartition_Open(); - if (pl == NULL) { - Debug("GetDiskInfo: ERROR: could not get partition list\n"); + char hwAddrString[NICINFO_MAC_LEN]; + unsigned char hwAddr[16]; + IanaIfType ifType; + Bool ret = FALSE; + u_int i; + + ASSERT(nicInfo); + ASSERT(nicIfIndex); + + if (NetUtil_GetHardwareAddress(ifIndex, hwAddr, sizeof hwAddr, + &ifType) != 6 || + ifType != IANA_IFTYPE_ETHERNETCSMACD) { return FALSE; } - for (i = 0; i < pl->size; i++) { - nextPartition = pl->partitions[i]; - if (!strlen(nextPartition.comment)) { - PPartitionEntry newPartitionList; - unsigned char *error; - error = WiperSinglePartition_GetSpace(&nextPartition, &freeBytes, &totalBytes); - if (strlen(error)) { - Debug("GetDiskInfo: ERROR: could not get space for partition %s: %s\n", - nextPartition.mountPoint, error); - goto out; - } - - if (strlen(nextPartition.mountPoint) + 1 > partNameSize) { - Debug("GetDiskInfo: ERROR: Partition name buffer too small\n"); - goto out; - } - - newPartitionList = realloc(di->partitionList, - (partCount + 1) * sizeof *di->partitionList); - if (newPartitionList == NULL) { - Debug("GetDiskInfo: ERROR: could not allocate partition list.\n"); - goto out; - } - di->partitionList = newPartitionList; - - Str_Strcpy((di->partitionList)[partCount].name, nextPartition.mountPoint, - partNameSize); - (di->partitionList)[partCount].freeBytes = freeBytes; - (di->partitionList)[partCount].totalBytes = totalBytes; - partCount++; + Str_Sprintf(hwAddrString, sizeof hwAddrString, + "%02x:%02x:%02x:%02x:%02x:%02x", + hwAddr[0], hwAddr[1], hwAddr[2], + hwAddr[3], hwAddr[4], hwAddr[5]); + + XDRUTIL_FOREACH(i, nicInfo, nics) { + GuestNicV3 *nic = XDRUTIL_GETITEM(nicInfo, nics, i); + if (!strcasecmp(nic->macAddress, hwAddrString)) { + *nicIfIndex = i; + ret = TRUE; + break; } } - di->numEntries = partCount; - success = TRUE; -out: - WiperPartition_Close(pl); - return success; + return ret; } +#endif // if defined linux || defined _WIN32 + + +/* + * XXX + */ + + +/** + * Return a copy of arbitrary memory. + * + * @param[in] source Source address. + * @param[in] sourceSize Number of bytes to allocate, copy. + * + * @return Pointer to newly allocated memory. + * + * @todo Determine if I'm duplicating functionality. + * @todo Move this to bora/lib/util or whatever. + */ +void * +Util_DupeThis(const void *source, + size_t sourceSize) +{ + void *dest; + + ASSERT(source); + + dest = Util_SafeMalloc(sourceSize); + memcpy(dest, source, sourceSize); + + return dest; +} diff --git a/open-vm-tools/lib/guestInfo/guestInfoInt.h b/open-vm-tools/lib/guestInfo/guestInfoInt.h index de39df738..21a84083b 100644 --- a/open-vm-tools/lib/guestInfo/guestInfoInt.h +++ b/open-vm-tools/lib/guestInfo/guestInfoInt.h @@ -31,19 +31,33 @@ #include "guestInfo.h" #include "guestrpc/nicinfo.h" +#if defined __FreeBSD__ || defined __sun__ || defined __APPLE__ +# include // struct sockaddr +#endif + Bool GuestInfoGetFqdn(int outBufLen, char fqdn[]); -Bool GuestInfoGetNicInfo(GuestNicList *nicInfo); +Bool GuestInfoGetNicInfo(NicInfoV3 *nicInfo); void GuestInfoMemset(void * mem, int value, unsigned int size); Bool GuestInfoGetDiskInfo(PGuestDiskInfo di); Bool GuestInfo_PerfMon(struct GuestMemInfo *vmStats); -GuestNic *GuestInfoAddNicEntry(GuestNicList *nicInfo, - const char macAddress[NICINFO_MAC_LEN]); -VmIpAddress *GuestInfoAddIpAddress(GuestNic *nic, - const char *ipAddr, - const uint32 af_type); -void GuestInfoAddSubnetMask(VmIpAddress *ipAddressEntry, - const uint32 subnetMaskBits, - Bool convertToMask); - +GuestNicV3 *GuestInfoAddNicEntry(NicInfoV3 *nicInfo, // IN/OUT + const char macAddress[NICINFO_MAC_LEN], // IN + DnsConfigInfo *dnsInfo); // IN + +IpAddressEntry *GuestInfoAddIpAddress(GuestNicV3 *nic, // IN/OUT + const struct sockaddr *sockAddr, // IN + InetAddressPrefixLength pfxLen, // IN + const IpAddressOrigin *origin, // IN + const IpAddressStatus *status); // IN +#if defined linux || defined _WIN32 +Bool GuestInfoGetNicInfoIfIndex(NicInfoV3 *nicInfo, // IN + int ifIndex, // IN + int *nicIfIndex); // OUT +#endif // if defined linux || defined _WIN32 +void GuestInfoSockaddrToTypedIpAddress(const struct sockaddr *sa, // IN + TypedIpAddress *typedIp); // OUT + +/* XXX */ +void * Util_DupeThis(const void *source, size_t sourceSize); #endif diff --git a/open-vm-tools/lib/guestInfo/guestInfoPosix.c b/open-vm-tools/lib/guestInfo/guestInfoPosix.c index a02a4c40d..991fdc5eb 100644 --- a/open-vm-tools/lib/guestInfo/guestInfoPosix.c +++ b/open-vm-tools/lib/guestInfo/guestInfoPosix.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (C) 1998 VMware, Inc. All rights reserved. + * 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 @@ -16,22 +16,16 @@ * *********************************************************/ - -/* - * guestInfoPosix.c -- - * - * Routines to get guest information. These are invoked by guestInfoServer - * which writes this information into Vmdb. +/** + * @file guestInfoPosix.c * + * Contains POSIX-specific bits of GuestInfo collector library. */ -#ifndef VMX86_DEVEL - -#endif - #include #include #include +#include #include #ifdef sun # include @@ -51,6 +45,56 @@ # include # endif #endif + +#include +#include +#include + +#ifdef __linux__ +# include +#endif + + +/* + * resolver(3) and IPv6: + * + * The ISC BIND resolver included various IPv6 implementations over time, but + * unfortunately the ISC hadn't bumped __RES accordingly. (__RES is -supposed- + * to behave as a version datestamp for the resolver interface.) Similarly + * the GNU C Library forked resolv.h and made modifications of their own, also + * without changing __RES. + * + * glibc 2.1.92 included a patch which provides IPv6 name server support by + * embedding in6_addr pointers in _res._u._ext. Since I only care about major + * and minor numbers, though, I'm going to condition this impl. on glibc 2.2. + * + * ISC, OTOH, provided accessing IPv6 servers via a res_getservers API. + * TTBOMK, this went public with BIND 8.3.0. Unfortunately __RES wasn't + * bumped for this release, so instead I'm going to assume that appearance with + * that release of a new macro, RES_F_DNS0ERR, implies this API is available. + * (For internal builds, we'll know instantly when a build breaks. The down- + * side is that this could cause some trouble for Open VM Tools users. ,_,) + * + * resolv.h version IPv6 API __RES + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * glibc 2.2+ _ext 19991006 + * BIND 8.3.0 getservers 19991006 + * BIND 8.3.4+ getservers 20030124(+?) + * + * To distinguish between the variants where __RES == 19991006, I'll + * discriminate on the existence of new macros included with the appropriate + * version. + */ + +#if defined __GLIBC__ +# if __GLIBC_PREREQ(2,2) +# define RESOLVER_IPV6_EXT +# endif // __GLIBC_PREREQ(2,2) +#elif (__RES > 19991006 || (__RES == 19991006 && defined RES_F_EDNS0ERR)) +# define RESOLVER_IPV6_GETSERVERS +#endif // if defined __GLIBC__ + + #include "util.h" #include "sys/utsname.h" #include "sys/ioctl.h" @@ -62,24 +106,33 @@ #include "guest_os.h" #include "guestApp.h" #include "guestInfo.h" +#include "xdrutil.h" +#include "slashProc.h" +#include "netutil.h" +#include "file.h" /* - *----------------------------------------------------------------------------- - * - * GuestInfoGetFqdn-- - * - * Return the guest's fully qualified domain name. - * This is just a thin wrapper around gethostname. - * - * Return value: - * Returns TRUE on success and FALSE on failure. - * Returns the guest's fully qualified domain name. + * Local functions + */ + + +#ifndef NO_DNET +static void RecordNetworkAddress(GuestNicV3 *nic, const struct addr *addr); +static int ReadInterfaceDetails(const struct intf_entry *entry, void *arg); +static Bool RecordResolverInfo(NicInfoV3 *nicInfo); +static void RecordResolverNS(DnsConfigInfo *dnsConfigInfo); +static Bool RecordRoutingInfo(NicInfoV3 *nicInfo); +#endif + + +/* + ****************************************************************************** + * GuestInfoGetFqdn -- */ /** * - * Side effects: - * None + * @copydoc GuestInfo_GetFqdn * - *----------------------------------------------------------------------------- + ****************************************************************************** */ Bool @@ -96,96 +149,118 @@ GuestInfoGetFqdn(int outBufLen, // IN: length of output buffer } -#ifndef NO_DNET /* - *----------------------------------------------------------------------------- + ****************************************************************************** + * GuestInfoGetNicInfo -- */ /** * - * RecordNetworkAddress -- + * @copydoc GuestInfo_GetNicInfo * - * Massages a dnet(3)-style interface address (IPv4 or IPv6) and stores it - * as part of a GuestNic structure. + ****************************************************************************** + */ + +Bool +GuestInfoGetNicInfo(NicInfoV3 *nicInfo) // OUT +{ +#ifndef NO_DNET + intf_t *intf; + + /* Get a handle to read the network interface configuration details. */ + if ((intf = intf_open()) == NULL) { + Debug("GuestInfo: Error, failed NULL result from intf_open()\n"); + return FALSE; + } + + if (intf_loop(intf, ReadInterfaceDetails, nicInfo) < 0) { + intf_close(intf); + Debug("GuestInfo: Error, negative result from intf_loop\n"); + return FALSE; + } + + intf_close(intf); + + if (!RecordResolverInfo(nicInfo)) { + return FALSE; + } + + if (!RecordRoutingInfo(nicInfo)) { + return FALSE; + } + + return TRUE; +#else + return FALSE; +#endif +} + + +/* + * Local functions + */ + + +#ifndef NO_DNET +/* + ****************************************************************************** + * RecordNetworkAddress -- */ /** * - * Results: - * If addr is IPv4 or IPv6, it will be appended to the GuestNic's list of - * IP addresses. + * @brief Massages a dnet(3)-style interface address (IPv4 or IPv6) and stores + * it as part of a GuestNicV3 structure. * - * Side effects: - * None. + * @param[in] nic Operand NIC. + * @param[in] addr dnet(3) address. * - *----------------------------------------------------------------------------- + ****************************************************************************** */ static void -RecordNetworkAddress(GuestNic *nic, // IN: operand NIC +RecordNetworkAddress(GuestNicV3 *nic, // IN: operand NIC const struct addr *addr) // IN: dnet(3) address to process { - char ipAddress[NICINFO_MAX_IP_LEN]; - VmIpAddress *ip = NULL; + struct sockaddr_storage ss; + struct sockaddr *sa = (struct sockaddr *)&ss; - switch (addr->addr_type) { - case ADDR_TYPE_IP: - /* - * GuestNicInfo clients expect IPv4 addresses and netmasks to be stored - * as strings in separate fields. As such, we'll use ip_ntop instead of - * addr_ntop to get a string without the netmask bits. - */ - ip_ntop(&addr->addr_ip, ipAddress, sizeof ipAddress); - ip = GuestInfoAddIpAddress(nic, ipAddress, INFO_IP_ADDRESS_FAMILY_IPV4); - if (ip) { - GuestInfoAddSubnetMask(ip, addr->addr_bits, TRUE); - } - break; - case ADDR_TYPE_IP6: - ip6_ntop(&addr->addr_ip6, ipAddress, sizeof ipAddress); - ip = GuestInfoAddIpAddress(nic, ipAddress, INFO_IP_ADDRESS_FAMILY_IPV6); - if (ip) { - GuestInfoAddSubnetMask(ip, addr->addr_bits, FALSE); - } - break; - default: - Debug("%s: Unknown address type: %hu\n", __func__, addr->addr_type); - break; - } + memset(&ss, 0, sizeof ss); + addr_ntos(addr, sa); + GuestInfoAddIpAddress(nic, sa, addr->addr_bits, NULL, NULL); } /* - *----------------------------------------------------------------------------- + ****************************************************************************** + * ReadInterfaceDetails -- */ /** * - * ReadInterfaceDetails -- + * @brief Callback function called by libdnet when iterating over all the NICs + * on the host. * - * Callback function called by libdnet when iterating over all the - * NICs on the host. + * @param[in] entry Current interface entry. + * @param[in] arg Pointer to NicInfoV3 container. * - * Return value: - * Returns 0 on success and -1 on failure. - * Adds the MAC addresses of all NICs and their corresponding IPs. + * @note New GuestNicV3 structures are added to the NicInfoV3 structure. * - * Side effects: - * Memory is allocated for each NIC, as well as IP addresses of all NICs - * on successful return. + * @retval 0 Success. + * @retval -1 Failure. * - *----------------------------------------------------------------------------- + ****************************************************************************** */ -int +static int ReadInterfaceDetails(const struct intf_entry *entry, // IN: current interface entry void *arg) // IN: Pointer to the GuestNicList { int i; - GuestNicList *nicInfo = arg; + NicInfoV3 *nicInfo = arg; - if ((entry->intf_type & INTF_TYPE_ETH) == INTF_TYPE_ETH) { - GuestNic *nic; + ASSERT(entry); + ASSERT(arg); + + if (entry->intf_type == INTF_TYPE_ETH) { + GuestNicV3 *nic = NULL; char macAddress[NICINFO_MAC_LEN]; Str_Sprintf(macAddress, sizeof macAddress, "%s", addr_ntoa(&entry->intf_link_addr)); - nic = GuestInfoAddNicEntry(nicInfo, macAddress); - - if (nic == NULL) { - return -1; - } + nic = GuestInfoAddNicEntry(nicInfo, macAddress, NULL); + ASSERT_MEM_ALLOC(nic); /* Record the "primary" address. */ if (entry->intf_addr.addr_type == ADDR_TYPE_IP || @@ -205,51 +280,351 @@ ReadInterfaceDetails(const struct intf_entry *entry, // IN: current interface e return 0; } -#endif /* - *----------------------------------------------------------------------------- + ****************************************************************************** + * RecordResolverInfo -- */ /** * - * GuestInfoGetNicInfo -- + * @brief Query resolver(3), mapping settings to DnsConfigInfo. * - * Return MAC addresses of all the NICs in the guest and their - * corresponding IP addresses. + * @param[out] nicInfo NicInfoV3 container. * - * Return value: - * Returns TRUE on success and FALSE on failure. - * Return MAC addresses of all NICs and their corresponding IPs. + * @retval TRUE Values collected, attached to @a nicInfo. + * @retval FALSE Something went wrong. @a nicInfo is unharmed. * - * Side effects: - * Memory is allocated for each NIC, as well as IP addresses of all NICs - * on successful return. + ****************************************************************************** + */ + +static Bool +RecordResolverInfo(NicInfoV3 *nicInfo) // OUT +{ + DnsConfigInfo *dnsConfigInfo = NULL; + char namebuf[DNSINFO_MAX_ADDRLEN + 1]; + char **s; + + if (res_init() == -1) { + return FALSE; + } + + dnsConfigInfo = Util_SafeCalloc(1, sizeof *dnsConfigInfo); + + /* + * Copy in the host name. + */ + if (!GuestInfoGetFqdn(sizeof namebuf, namebuf)) { + goto fail; + } + dnsConfigInfo->hostName = + Util_SafeCalloc(1, sizeof *dnsConfigInfo->hostName); + *dnsConfigInfo->hostName = Util_SafeStrdup(namebuf); + + /* + * Repeat with the domain name. + */ + dnsConfigInfo->domainName = + Util_SafeCalloc(1, sizeof *dnsConfigInfo->domainName); + *dnsConfigInfo->domainName = Util_SafeStrdup(_res.defdname); + + /* + * Name servers. + */ + RecordResolverNS(dnsConfigInfo); + + /* + * Search suffixes. + */ + for (s = _res.dnsrch; *s; s++) { + DnsHostname *suffix = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, searchSuffixes, 1); + ASSERT_MEM_ALLOC(suffix); + *suffix = Util_SafeStrdup(*s); + } + + /* + * "Commit" dnsConfigInfo to nicInfo. + */ + nicInfo->dnsConfigInfo = dnsConfigInfo; + + return TRUE; + +fail: + VMX_XDR_FREE(xdr_DnsConfigInfo, dnsConfigInfo); + free(dnsConfigInfo); + return FALSE; +} + + +/* + ****************************************************************************** + * RecordResolverNS -- */ /** + * + * @brief Copies name servers used by resolver(3) to @a dnsConfigInfo. * - *----------------------------------------------------------------------------- + * @param[out] dnsConfigInfo Destination DnsConfigInfo container. + * + ****************************************************************************** */ -Bool -GuestInfoGetNicInfo(GuestNicList *nicInfo) // OUT +static void +RecordResolverNS(DnsConfigInfo *dnsConfigInfo) // IN { -#ifndef NO_DNET - intf_t *intf; + int i; - memset(nicInfo, 0, sizeof *nicInfo); +#if defined RESOLVER_IPV6_GETSERVERS + { + union res_sockaddr_union *ns; + ns = Util_SafeCalloc(_res.nscount, sizeof *ns); + if (res_getservers(&_res, ns, _res.nscount) != _res.nscount) { + Warning("%s: res_getservers failed.\n", __func__); + return; + } + for (i = 0; i < _res.nscount; i++) { + struct sockaddr *sa = (struct sockaddr *)&ns[i]; + if (sa->sa_family == AF_INET || sa->sa_family == AF_INET6) { + TypedIpAddress *ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1); + ASSERT_MEM_ALLOC(ip); + GuestInfoSockaddrToTypedIpAddress(sa, ip); + } + } + } +#else // if defined RESOLVER_IPV6_GETSERVERS + { + /* + * Name servers (IPv4). + */ + for (i = 0; i < MAXNS; i++) { + struct sockaddr_in *sin = &_res.nsaddr_list[i]; + if (sin->sin_family == AF_INET) { + TypedIpAddress *ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1); + ASSERT_MEM_ALLOC(ip); + GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin, ip); + } + } +# if defined RESOLVER_IPV6_EXT + /* + * Name servers (IPv6). + */ + for (i = 0; i < MAXNS; i++) { + struct sockaddr_in6 *sin6 = _res._u._ext.nsaddrs[i]; + if (sin6) { + TypedIpAddress *ip = XDRUTIL_ARRAYAPPEND(dnsConfigInfo, serverList, 1); + ASSERT_MEM_ALLOC(ip); + GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6, ip); + } + } +# endif // if defined RESOLVER_IPV6_EXT + } +#endif // if !defined RESOLVER_IPV6_GETSERVERS +} - /* Get a handle to read the network interface configuration details. */ - if ((intf = intf_open()) == NULL) { - Debug("GuestInfo: Error, failed NULL result from intf_open()\n"); + +#if defined __linux__ +/* + ****************************************************************************** + * RecordRoutingInfoIPv4 -- */ /** + * + * @brief Query the IPv4 routing subsystem and pack up contents + * (struct rtentry) into InetCidrRouteEntries. + * + * @param[out] nicInfo NicInfoV3 container. + * + * @note Do not call this routine without first populating @a nicInfo 's NIC + * list. + * + * @retval TRUE Values collected, attached to @a nicInfo. + * @retval FALSE Something went wrong. @a nicInfo is unharmed. + * + ****************************************************************************** + */ + +static Bool +RecordRoutingInfoIPv4(NicInfoV3 *nicInfo) +{ + GPtrArray *routes = NULL; + guint i; + Bool ret = FALSE; + + if ((routes = SlashProcNet_GetRoute()) == NULL) { return FALSE; } - if (intf_loop(intf, ReadInterfaceDetails, nicInfo) < 0) { - intf_close(intf); - Debug("GuestInfo: Error, negative result from intf_loop\n"); + for (i = 0; i < routes->len; i++) { + struct rtentry *rtentry; + struct sockaddr_in *sin_dst; + struct sockaddr_in *sin_gateway; + struct sockaddr_in *sin_genmask; + InetCidrRouteEntry *icre; + uint32_t ifIndex; + + rtentry = g_ptr_array_index(routes, i); + + if ((rtentry->rt_flags & RTF_UP) == 0 || + !GuestInfoGetNicInfoIfIndex(nicInfo, + if_nametoindex(rtentry->rt_dev), + &ifIndex)) { + continue; + } + + icre = XDRUTIL_ARRAYAPPEND(nicInfo, routes, 1); + ASSERT_MEM_ALLOC(icre); + + sin_dst = (struct sockaddr_in *)&rtentry->rt_dst; + sin_gateway = (struct sockaddr_in *)&rtentry->rt_gateway; + sin_genmask = (struct sockaddr_in *)&rtentry->rt_genmask; + + GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin_dst, + &icre->inetCidrRouteDest); + + addr_stob((struct sockaddr *)sin_genmask, + (uint16_t *)&icre->inetCidrRoutePfxLen); + + /* + * Gateways are optional (ex: one can bind a route to an interface w/o + * specifying a next hop address). + */ + if (rtentry->rt_flags & RTF_GATEWAY) { + TypedIpAddress *ip = Util_SafeCalloc(1, sizeof *ip); + GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin_gateway, ip); + icre->inetCidrRouteNextHop = ip; + } + + /* + * Interface, metric. + */ + icre->inetCidrRouteIfIndex = ifIndex; + icre->inetCidrRouteMetric = rtentry->rt_metric; + } + + ret = TRUE; + + SlashProcNet_FreeRoute(routes); + return ret; +} + + +/* + ****************************************************************************** + * RecordRoutingInfoIPv6 -- */ /** + * + * @brief Query the IPv6 routing subsystem and pack up contents + * (struct in6_rtmsg) into InetCidrRouteEntries. + * + * @param[out] nicInfo NicInfoV3 container. + * + * @note Do not call this routine without first populating @a nicInfo 's NIC + * list. + * + * @retval TRUE Values collected, attached to @a nicInfo. + * @retval FALSE Something went wrong. @a nicInfo is unharmed. + * + ****************************************************************************** + */ + +static Bool +RecordRoutingInfoIPv6(NicInfoV3 *nicInfo) +{ + GPtrArray *routes = NULL; + guint i; + Bool ret = FALSE; + + if ((routes = SlashProcNet_GetRoute6()) == NULL) { return FALSE; } - intf_close(intf); + for (i = 0; i < routes->len; i++) { + struct sockaddr_storage ss; + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; + struct in6_rtmsg *in6_rtmsg; + InetCidrRouteEntry *icre; + uint32_t ifIndex = -1; + + in6_rtmsg = g_ptr_array_index(routes, i); + + if ((in6_rtmsg->rtmsg_flags & RTF_UP) == 0 || + !GuestInfoGetNicInfoIfIndex(nicInfo, in6_rtmsg->rtmsg_ifindex, + &ifIndex)) { + continue; + } + + icre = XDRUTIL_ARRAYAPPEND(nicInfo, routes, 1); + ASSERT_MEM_ALLOC(icre); + + /* + * Destination. + */ + sin6->sin6_family = AF_INET6; + sin6->sin6_addr = in6_rtmsg->rtmsg_dst; + GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6, + &icre->inetCidrRouteDest); + + icre->inetCidrRoutePfxLen = in6_rtmsg->rtmsg_dst_len; + + /* + * Next hop. + */ + if (in6_rtmsg->rtmsg_flags & RTF_GATEWAY) { + TypedIpAddress *ip = Util_SafeCalloc(1, sizeof *ip); + sin6->sin6_addr = in6_rtmsg->rtmsg_gateway; + GuestInfoSockaddrToTypedIpAddress((struct sockaddr *)sin6, ip); + icre->inetCidrRouteNextHop = ip; + } + + /* + * Interface, metric. + */ + icre->inetCidrRouteIfIndex = ifIndex; + icre->inetCidrRouteMetric = in6_rtmsg->rtmsg_metric; + } + + ret = TRUE; + + SlashProcNet_FreeRoute6(routes); + return ret; +} + + +/* + ****************************************************************************** + * RecordRoutingInfo -- */ /** + * + * @brief Query the routing subsystem and pack up contents into + * InetCidrRouteEntries. + * + * @param[out] nicInfo NicInfoV3 container. + * + * @note Do not call this routine without first populating @a nicInfo 's NIC + * list. + * + * @retval TRUE Values collected, attached to @a nicInfo. + * @retval FALSE Something went wrong. + * + ****************************************************************************** + */ + +static Bool +RecordRoutingInfo(NicInfoV3 *nicInfo) +{ + Bool ret = TRUE; + + if (File_Exists("/proc/net/route") && !RecordRoutingInfoIPv4(nicInfo)) { + Warning("%s: Unable to collect IPv4 routing table.\n", __func__); + ret = FALSE; + } + + if (File_Exists("/proc/net/ipv6_route") && !RecordRoutingInfoIPv6(nicInfo)) { + Warning("%s: Unable to collect IPv6 routing table.\n", __func__); + ret = FALSE; + } + + return ret; +} + +#else // if defined __linux__ +static Bool +RecordRoutingInfo(NicInfoV3 *nicInfo) +{ return TRUE; -#else - return FALSE; -#endif } +#endif // else + +#endif // ifndef NO_DNET diff --git a/open-vm-tools/lib/guestRpc/ghiCommonDefines.h b/open-vm-tools/lib/guestRpc/ghiCommonDefines.h index e643375f2..b76bb2dc5 100644 --- a/open-vm-tools/lib/guestRpc/ghiCommonDefines.h +++ b/open-vm-tools/lib/guestRpc/ghiCommonDefines.h @@ -38,4 +38,9 @@ */ #define GHI_HANDLERS_ACTIONURI_MAX_PATH 1040 +/* + * Maximum length for a guest app hash value (usually much shorter). + */ +#define GHI_EXEC_INFO_HASH_MAX_LEN 1024 + #endif // ifndef _GHI_COMMON_DEFINES_H_ diff --git a/open-vm-tools/lib/guestRpc/ghiGetExecInfoHash.x b/open-vm-tools/lib/guestRpc/ghiGetExecInfoHash.x index 989ed0164..14d73a53e 100644 --- a/open-vm-tools/lib/guestRpc/ghiGetExecInfoHash.x +++ b/open-vm-tools/lib/guestRpc/ghiGetExecInfoHash.x @@ -25,8 +25,6 @@ #include "ghiCommonDefines.h" -#define GHI_EXEC_INFO_HASH_MAX_LEN 1024 - /* * Enumerates the different versions of the messages. */ diff --git a/open-vm-tools/lib/guestRpc/nicinfo.x b/open-vm-tools/lib/guestRpc/nicinfo.x index 743282334..323d1bc3d 100644 --- a/open-vm-tools/lib/guestRpc/nicinfo.x +++ b/open-vm-tools/lib/guestRpc/nicinfo.x @@ -28,7 +28,9 @@ * version one is legacy code we can't change. */ enum NicInfoVersion { - NIC_INFO_V2 = 2 + NIC_INFO_V1 = 1, /* XXX Not represented here. */ + NIC_INFO_V2 = 2, + NIC_INFO_V3 = 3 }; /* @@ -42,11 +44,16 @@ const NICINFO_MAX_NICS = 16; /* MAC Addresses are "AA:BB:CC:DD:EE:FF" = 18 bytes. */ const NICINFO_MAC_LEN = 18; +/* + * Corresponds to public/guestInfo.h::GuestInfoIPAddressFamilyType. + */ +enum NicInfoAddrType { + NICINFO_ADDR_IPV4 = 0, + NICINFO_ADDR_IPV6 = 1 +}; + struct VmIpAddress { - /* - * Corresponds to public/guestInfo.h::GuestInfoIPAddressFamilyType. - */ - uint32 addressFamily; + NicInfoAddrType addressFamily; Bool dhcpEnabled; char ipAddress[NICINFO_MAX_IP_LEN]; /* @@ -69,6 +76,242 @@ struct GuestNicList { struct GuestNic nics; }; + +/* + *----------------------------------------------------------------------------- + * + * NIC Info version 3. + * + * V3 adds routing, DNS, and WINS information to the NIC list. + * + *----------------------------------------------------------------------------- + */ + + +/* + * IP v4 and v6 addressing. + * + * These types were redefined primarily to allow much more efficient wire + * encoding. + */ + + +/* + * See RFC 4001, InetAddress. + */ +const INET_ADDRESS_MAX_LEN = 255; +typedef opaque InetAddress; + + +/* + * See RFC 4001, InetAddressType. + */ +enum InetAddressType { + IAT_UNKNOWN = 0, + IAT_IPV4 = 1, + IAT_IPV6 = 2, + IAT_IPV4Z = 3, + IAT_IPV6Z = 4, + IAT_DNS = 16 +}; + + +/* + * See RFC 4001, InetAddressPrefixLength. + */ +typedef unsigned int InetAddressPrefixLength; + + +/* + * See RFC 4293, IpAddressOriginTC. + */ +enum IpAddressOrigin { + IAO_OTHER = 1, + IAO_MANUAL = 2, + IAO_DHCP = 4, + IAO_LINKLAYER = 5, + IAO_RANDOM = 6 +}; + + +/* + * See RFC 4293, IpAddressStatusTC. + * + * "The status of an address. Most of the states correspond to states + * from the IPv6 Stateless Address Autoconfiguration protocol. + * ... + * "In the absence of other information, an IPv4 address is always + * preferred(1)." + */ +enum IpAddressStatus { + IAS_PREFERRED = 1, + IAS_DEPRECATED = 2, + IAS_INVALID = 3, + IAS_INACCESSIBLE = 4, + IAS_UNKNOWN = 5, + IAS_TENTATIVE = 6, + IAS_DUPLICATE = 7, + IAS_OPTIMISTIC = 8 +}; + + +/* + * Convenient type for lists of addresses. + */ +struct TypedIpAddress { + InetAddressType ipAddressAddrType; + InetAddress ipAddressAddr; +}; + + +/* + * See RFC 4293, IpAddressEntry. + * + * "An address mapping for a particular interface." + * + * We deviate from the RFC in a few places: + * - The prefix length is listed explicitly here rather than reference + * a separate prefix table. + * - Interface indices aren't included as this structure is dependent + * upon/encapsulated by a GuestNicV3 structure. + */ +struct IpAddressEntry { + TypedIpAddress ipAddressAddr; + InetAddressPrefixLength ipAddressPrefixLength; + IpAddressOrigin *ipAddressOrigin; + IpAddressStatus *ipAddressStatus; +}; + + +/* + * Runtime DNS resolver state. + */ + + +/* + * Quoth RFC 2181 §11 (Name Syntax): + * "The length of any one label is limited to between 1 and 63 octets. A + * full domain name is limited to 255 octets (including the separators)." + */ +const DNSINFO_MAX_ADDRLEN = 255; +typedef string DnsHostname; + + +/* + * Arbitrary limits. + */ +const DNSINFO_MAX_SUFFIXES = 10; +const DNSINFO_MAX_SERVERS = 16; + +struct DnsConfigInfo { + DnsHostname *hostName; + DnsHostname *domainName; + TypedIpAddress serverList; + DnsHostname searchSuffixes; +}; + + +/* + * Runtime WINS resolver state. Addresses are assumed to be IPv4 only. + */ + +struct WinsConfigInfo { + TypedIpAddress primary; + TypedIpAddress secondary; +}; + + +/* + * Runtime routing tables. + */ + + +/* + * Arbitrary limit. + */ +const NICINFO_MAX_ROUTES = 100; + + +/* + * See RFC 4292 for details. + */ +enum InetCidrRouteType { + ICRT_OTHER = 1, + ICRT_REJECT = 2, + ICRT_LOCAL = 3, + ICRT_REMOTE = 4 +}; + +struct InetCidrRouteEntry { + TypedIpAddress inetCidrRouteDest; + InetAddressPrefixLength inetCidrRoutePfxLen; + + /* + * Next hop isn't mandatory. + */ + TypedIpAddress *inetCidrRouteNextHop; + + /* + * inetCidrRouteProto is omitted as we're concerned only with static/ + * netmgmt routes. + */ + + /* This is an array index into GuestNicListV3::nics. */ + uint32 inetCidrRouteIfIndex; + + /* XXX Do we really need this? */ + InetCidrRouteType inetCidrRouteType; + + /* -1 == unused. */ + uint32 inetCidrRouteMetric; +}; + + +/* + * Fun with DHCP + */ + +const DHCP_MAX_CONFIG_SIZE = 16384; + +struct DhcpConfigInfo { + bool enabled; + string dhcpSettings; +}; + + +/* + * Top-level containers. + */ + + +/* + * Describes a single NIC. + */ + +struct GuestNicV3 { + string macAddress; + IpAddressEntry ips; + DnsConfigInfo *dnsConfigInfo; + WinsConfigInfo *winsConfigInfo; + DhcpConfigInfo *dhcpConfigInfov4; + DhcpConfigInfo *dhcpConfigInfov6; +}; + + +/* + * Attempts to model general network state. + */ + +struct NicInfoV3 { + GuestNicV3 nics; + InetCidrRouteEntry routes; + DnsConfigInfo *dnsConfigInfo; + WinsConfigInfo *winsConfigInfo; + DhcpConfigInfo *dhcpConfigInfov4; + DhcpConfigInfo *dhcpConfigInfov6; +}; + + /* * This defines the protocol for a "nic info" message. The union allows * us to create new versions of the protocol later by creating new values @@ -81,5 +324,6 @@ struct GuestNicList { union GuestNicProto switch (NicInfoVersion ver) { case NIC_INFO_V2: struct GuestNicList *nicsV2; +case NIC_INFO_V3: + struct NicInfoV3 *nicInfoV3; }; - diff --git a/open-vm-tools/lib/hgfsBd/hgfsBd.c b/open-vm-tools/lib/hgfsBd/hgfsBd.c index a64db5a18..4f9e4596f 100644 --- a/open-vm-tools/lib/hgfsBd/hgfsBd.c +++ b/open-vm-tools/lib/hgfsBd/hgfsBd.c @@ -306,8 +306,8 @@ HgfsBd_Enabled(RpcOut *out, // IN: RPCI Channel char *requestPacket) // IN: Buffer (obtained from HgfsBd_GetBuf) { char const *replyPacket; // Buffer returned by HgfsBd_Dispatch - size_t packetSize; - int error; + size_t replyLen; + Bool success; /* * Send a bogus (empty) request to the VMX. If hgfs is disabled on @@ -316,16 +316,14 @@ HgfsBd_Enabled(RpcOut *out, // IN: RPCI Channel * (it will be an error packet because our request was malformed, * but we just discard it anyway). */ - packetSize = 0; - error = HgfsBd_Dispatch(out, - requestPacket, - &packetSize, - &replyPacket); - if (error < 0) { - return FALSE; + success = RpcOut_send(out, requestPacket - HGFS_CLIENT_CMD_LEN, + HGFS_CLIENT_CMD_LEN, + &replyPacket, &replyLen); + if (success == TRUE) { + ASSERT(replyLen <= HGFS_LARGE_PACKET_MAX); } - return TRUE; + return success; } diff --git a/open-vm-tools/lib/hgfsHelper/Makefile.am b/open-vm-tools/lib/hgfsHelper/Makefile.am new file mode 100644 index 000000000..1f37ff88a --- /dev/null +++ b/open-vm-tools/lib/hgfsHelper/Makefile.am @@ -0,0 +1,22 @@ +################################################################################ +### Copyright 2009 VMware, Inc. All rights reserved. +### +### This program is free software; you can redistribute it and/or modify +### it under the terms of version 2 of the GNU General Public License as +### published by the Free Software Foundation. +### +### 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 +### GNU General Public License for more details. +### +### You should have received a copy of the GNU 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 +################################################################################ + +noinst_LTLIBRARIES = libHgfsHelper.la + +libHgfsHelper_la_SOURCES = +libHgfsHelper_la_SOURCES += hgfsHelperPosix.c + diff --git a/open-vm-tools/lib/hgfsHelper/hgfsHelperPosix.c b/open-vm-tools/lib/hgfsHelper/hgfsHelperPosix.c new file mode 100644 index 000000000..533d8fc65 --- /dev/null +++ b/open-vm-tools/lib/hgfsHelper/hgfsHelperPosix.c @@ -0,0 +1,104 @@ +/********************************************************* + * Copyright (C) 2009 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. + * + *********************************************************/ + +/* + * hgfsHelperPosix.c -- + * + * Provides a posix helper library for guest applications to access + * the HGFS file system. + * + */ + +#if !defined __linux__ && !defined __FreeBSD__ && !defined sun && !defined __APPLE__ +# error This file should not be compiled +#endif + +#include "vmware.h" +#include "debug.h" + +#include "hgfsHelper.h" + +#if defined __linux__ +#define HGFSHLPR_DEFAULT_MOUNT_PATH "/mnt/hgfs" +#elif defined sun +#define HGFSHLPR_DEFAULT_MOUNT_PATH "/hgfs" +#elif defined __APPLE__ +#define HGFSHLPR_DEFAULT_MOUNT_PATH "/Volumes/Shared Folders" +#endif + + +/* + *----------------------------------------------------------------------------- + * + * HgfsHlpr_QuerySharesDefaultRootPath -- + * + * Queries the driver for its share's root paths. + * Currently only one is expected to be supported + * and returned, although later versions may not. + * E.g. "/mnt/hgfs" is the root path to + * the HGFS shares. + * + * Results: + * TRUE always. + * + * Side Effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +Bool +HgfsHlpr_QuerySharesDefaultRootPath(Unicode *hgfsRootPath) +{ +#if defined __FreeBSD__ + return FALSE; +#else + ASSERT(hgfsRootPath != NULL); + + *hgfsRootPath = Unicode_AllocWithUTF8(HGFSHLPR_DEFAULT_MOUNT_PATH); + + Debug("%s: HGFS shares root path name \"%s\"\n", + __FUNCTION__, UTF8(*hgfsRootPath)); + + return TRUE; +#endif +} + + +/* + *----------------------------------------------------------------------------- + * + * HgfsHlpr_FreeSharesRootPath -- + * + * Frees the share's root paths previously returned + * to the caller from the HgfsHlpr_QuerySharesRootPath. + * + * Results: + * None. + * + * Side Effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +void +HgfsHlpr_FreeSharesRootPath(Unicode hgfsRootPath) +{ + Unicode_Free(hgfsRootPath); +} diff --git a/open-vm-tools/lib/hgfsServer/hgfsServer.c b/open-vm-tools/lib/hgfsServer/hgfsServer.c index 352e41e6a..63dfb74a1 100644 --- a/open-vm-tools/lib/hgfsServer/hgfsServer.c +++ b/open-vm-tools/lib/hgfsServer/hgfsServer.c @@ -56,7 +56,6 @@ * NOTE: This flag is only meant to be used while testing. This should * _always_ be undefined when checking code in. */ - #if 0 #define HGFS_ASSERT_CLIENT(op) \ do { \ @@ -76,7 +75,6 @@ * NOTE: This flag is only meant to be used while testing. This should * _always_ be undefined when checking code in. */ - #if 0 #define HGFS_ASSERT_MINIMUM_OP(op) \ do { \ @@ -186,9 +184,6 @@ static Bool hgfsChangeNotificationSupported = FALSE; /* Local functions. */ -static Bool HgfsServerCheckPathPrefix(const char *path, - const char *share, - size_t shareLen); static void HgfsInvalidateSessionObjects(DblLnkLst_Links *shares, HgfsSessionInfo *session); static Bool HgfsAddToCacheInternal(HgfsHandle handle, @@ -206,6 +201,7 @@ static HgfsHandle HgfsSearch2SearchHandle(HgfsSearch const *search); static HgfsSearch *HgfsAddNewSearch(char const *utf8Dir, DirectorySearchType type, char const *utf8ShareName, + char const *rootDir, HgfsSessionInfo *session); static void HgfsDumpAllSearches(HgfsSessionInfo *session); static void HgfsDumpAllNodes(HgfsSessionInfo *session); @@ -493,7 +489,8 @@ HgfsDumpAllNodes(HgfsSessionInfo *session) // IN: session info Bool HgfsHandle2FileDesc(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: Session info - fileDesc *fd) // OUT: OS handle (file descriptor) + fileDesc *fd, // OUT: OS handle (file descriptor) + void **fileCtx) // OUT: OS file context { Bool found = FALSE; HgfsFileNode *fileNode = NULL; @@ -505,6 +502,9 @@ HgfsHandle2FileDesc(HgfsHandle handle, // IN: Hgfs file handle } *fd = fileNode->fileDesc; + if (fileCtx) { + *fileCtx = fileNode->fileCtx; + } found = TRUE; exit: @@ -767,6 +767,37 @@ HgfsHandle2FileName(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session,// IN: Session info char **fileName, // OUT: UTF8 file name size_t *fileNameSize) // OUT: UTF8 file name size +{ + Bool unused1, unused2; + return HgfsHandle2FileNameMode(handle, session, &unused1, &unused2, fileName, + fileNameSize); +} + +/* + *----------------------------------------------------------------------------- + * + * HgfsHandle2FileNameMode -- + * + * Given an OS handle/fd, return file's hgfs name and permissions + * associated with the corresponding shared folder. + * + * Results: + * TRUE if the node was found. + * FALSE otherwise. + * + * Side effects: + * Allocates memory and makes a copy of the file name. + * + *----------------------------------------------------------------------------- + */ + +Bool +HgfsHandle2FileNameMode(HgfsHandle handle, // IN: Hgfs file handle + HgfsSessionInfo *session,// IN: Session info + Bool *readPermissions, // OUT: shared folder permissions + Bool *writePermissions, // OUT: shared folder permissions + char **fileName, // OUT: UTF8 file name + size_t *fileNameSize) // OUT: UTF8 file name size { Bool found = FALSE; HgfsFileNode *existingFileNode = NULL; @@ -787,6 +818,8 @@ HgfsHandle2FileName(HgfsHandle handle, // IN: Hgfs file handle if (name == NULL) { goto exit_unlock; } + *readPermissions = existingFileNode->shareInfo.readPermissions; + *writePermissions = existingFileNode->shareInfo.writePermissions; nameSize = existingFileNode->utf8NameLen; memcpy(name, existingFileNode->utf8Name, nameSize); name[nameSize] = '\0'; @@ -836,7 +869,6 @@ HgfsFileHasServerLock(const char *utf8Name, // IN: Name in UTF8 SyncMutex_Lock(&session->nodeArrayLock); for (i = 0; i < session->numNodes; i++) { HgfsFileNode *existingFileNode = &session->nodeArray[i]; - if ((existingFileNode->state == FILENODE_STATE_IN_USE_CACHED) && (existingFileNode->serverLock != HGFS_LOCK_NONE) && (!stricmp(existingFileNode->utf8Name, utf8Name))) { @@ -912,6 +944,7 @@ HgfsGetNodeCopy(HgfsHandle handle, // IN: Hgfs file handle copy->flags = original->flags; copy->state = original->state; copy->handle = original->handle; + copy->fileCtx = original->fileCtx; found = TRUE; exit: @@ -1025,7 +1058,8 @@ exit: Bool HgfsUpdateNodeFileDesc(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: Session info - fileDesc fd) // OUT: OS handle (file desc) + fileDesc fd, // IN: OS handle (file desc) + void *fileCtx) // IN: OS file context { HgfsFileNode *node; Bool updated = FALSE; @@ -1037,6 +1071,7 @@ HgfsUpdateNodeFileDesc(HgfsHandle handle, // IN: Hgfs file handle } node->fileDesc = fd; + node->fileCtx = fileCtx; updated = TRUE; exit: @@ -1198,7 +1233,6 @@ HgfsServerCheckOpenFlagsForShare(HgfsFileOpenInfo *openInfo,// IN: Hgfs file han * if the file does not exist, which it is okay, as creating * a new file is not allowed and should be failed. */ - *flags = HGFS_OPEN; } } @@ -1287,7 +1321,6 @@ HgfsGetNewNode(HgfsSessionInfo *session) // IN: session info * This has to be unsigned and with maximum bit length. This is * required to take care of "negative" differences as well. */ - uintptr_t ptrDiff; if (DOLOG(4)) { @@ -1330,7 +1363,6 @@ HgfsGetNewNode(HgfsSessionInfo *session) // IN: session info /* * Rebase the links of all file nodes */ - for (i = 0; i < session->numNodes; i++) { HgfsServerRebase(newMem[i].links.prev, DblLnkLst_Links) HgfsServerRebase(newMem[i].links.next, DblLnkLst_Links) @@ -1356,6 +1388,7 @@ HgfsGetNewNode(HgfsSessionInfo *session) // IN: session info newMem[i].state = FILENODE_STATE_UNUSED; newMem[i].utf8Name = NULL; newMem[i].utf8NameLen = 0; + newMem[i].fileCtx = NULL; /* Append at the end of the list */ DblLnkLst_LinkLast(&session->nodeFreeList, &newMem[i].links); @@ -1416,6 +1449,8 @@ HgfsRemoveFileNode(HgfsFileNode *node, // IN: file node } node->utf8Name = NULL; node->state = FILENODE_STATE_UNUSED; + ASSERT(node->fileCtx == NULL); + node->fileCtx = NULL; /* Prepend at the beginning of the list */ DblLnkLst_LinkFirst(&session->nodeFreeList, &node->links); @@ -1510,6 +1545,7 @@ HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo, // IN: open info struct HgfsSessionInfo *session) // IN: session info { HgfsFileNode *newNode; + char* rootDir; ASSERT(openInfo); ASSERT(localId); @@ -1529,7 +1565,6 @@ HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo, // IN: open info struct /* Set new node's fields */ if (!HgfsServerGetOpenMode(openInfo, &newNode->mode)) { HgfsRemoveFileNode(newNode, session); - return NULL; } @@ -1537,12 +1572,10 @@ HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo, // IN: open info struct * Save a copy of the share name so we can look up its * access mode at various times over the node's lifecycle. */ - newNode->shareName = malloc(shareNameLen + 1); if (newNode->shareName == NULL) { LOG(4, ("%s: out of memory\n", __FUNCTION__)); HgfsRemoveFileNode(newNode, session); - return NULL; } memcpy(newNode->shareName, shareName, shareNameLen); @@ -1554,12 +1587,22 @@ HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo, // IN: open info struct if (newNode->utf8Name == NULL) { LOG(4, ("%s: out of memory\n", __FUNCTION__)); HgfsRemoveFileNode(newNode, session); - return NULL; } memcpy(newNode->utf8Name, openInfo->utf8Name, newNode->utf8NameLen); newNode->utf8Name[newNode->utf8NameLen] = '\0'; + newNode->shareInfo.rootDirLen = strlen(openInfo->shareInfo.rootDir); + rootDir = malloc(newNode->shareInfo.rootDirLen + 1); + if (rootDir == NULL) { + LOG(4, ("HgfsAddNewFileNode: out of memory\n")); + HgfsRemoveFileNode(newNode, session); + return NULL; + } + memcpy(rootDir, openInfo->shareInfo.rootDir, newNode->shareInfo.rootDirLen); + rootDir[newNode->shareInfo.rootDirLen] = '\0'; + newNode->shareInfo.rootDir = rootDir; + newNode->handle = HgfsServerGetNextHandleCounter(); newNode->localId = *localId; newNode->fileDesc = fileDesc; @@ -1579,10 +1622,11 @@ HgfsAddNewFileNode(HgfsFileOpenInfo *openInfo, // IN: open info struct newNode->serverLock = openInfo->acquiredLock; newNode->state = FILENODE_STATE_IN_USE_NOT_CACHED; + newNode->shareInfo.readPermissions = openInfo->shareInfo.readPermissions; + newNode->shareInfo.writePermissions = openInfo->shareInfo.writePermissions; LOG(4, ("%s: got new node, handle %u\n", __FUNCTION__, HgfsFileNode2Handle(newNode))); - return newNode; } @@ -1619,7 +1663,6 @@ HgfsAddToCacheInternal(HgfsHandle handle, // IN: HGFS file handle if (HgfsIsCachedInternal(handle, session)) { ASSERT((node = HgfsHandle2FileNode(handle, session)) && node->state == FILENODE_STATE_IN_USE_CACHED); - return TRUE; } @@ -1714,12 +1757,12 @@ HgfsRemoveFromCacheInternal(HgfsHandle handle, // IN: Hgfs handle to the * Instead, we'll just await the lobotomization of the node cache to * really fix this. */ - - if (HgfsCloseFile(node->fileDesc)) { + if (HgfsCloseFile(node->fileDesc, node->fileCtx)) { LOG(4, ("%s: Could not close fd %u\n", __FUNCTION__, node->fileDesc)); return FALSE; } + node->fileCtx = NULL; /* * If we have just removed the node then the number of used nodes better @@ -1775,7 +1818,6 @@ HgfsIsCachedInternal(HgfsHandle handle, // IN: Structure representing fi /* * Move this node to the end of the list. */ - DblLnkLst_Unlink1(&node->links); DblLnkLst_LinkLast(&session->nodeCachedList, &node->links); @@ -1927,6 +1969,8 @@ HgfsGetNewSearch(HgfsSessionInfo *session) // IN: session info newMem[i].utf8DirLen = 0; newMem[i].utf8ShareName = NULL; newMem[i].utf8ShareNameLen = 0; + newMem[i].shareInfo.rootDir = NULL; + newMem[i].shareInfo.rootDirLen = 0; newMem[i].dents = NULL; newMem[i].numDents = 0; @@ -2070,6 +2114,7 @@ HgfsSearch * HgfsAddNewSearch(char const *utf8Dir, // IN: UTF8 name of dir to search in DirectorySearchType type, // IN: What kind of search is this? char const *utf8ShareName, // IN: Share name containing the directory + char const *rootDir, // IN: Root directory for the share HgfsSessionInfo *session) // IN: Session info { HgfsSearch *newSearch; @@ -2105,9 +2150,15 @@ HgfsAddNewSearch(char const *utf8Dir, // IN: UTF8 name of dir to search in return NULL; } + newSearch->shareInfo.rootDirLen = strlen(rootDir); + newSearch->shareInfo.rootDir = strdup(rootDir); + if (newSearch->shareInfo.rootDir == NULL) { + HgfsRemoveSearchInternal(newSearch, session); + return NULL; + } + LOG(4, ("%s: got new search, handle %u\n", __FUNCTION__, HgfsSearch2SearchHandle(newSearch))); - return newSearch; } @@ -2153,6 +2204,7 @@ HgfsRemoveSearchInternal(HgfsSearch *search, // IN: search free(search->utf8Dir); free(search->utf8ShareName); + free((char*)search->shareInfo.rootDir); /* Prepend at the beginning of the list */ DblLnkLst_LinkFirst(&session->searchFreeList, &search->links); @@ -2274,7 +2326,6 @@ HgfsGetSearchResult(HgfsHandle handle, // IN: Handle to search * at the top of hgfsServerInt.h, you'll see that on Windows we only * define d_reclen and d_name, as those are the only fields we need. */ - dent->d_reclen = originalDent->d_reclen; memcpy(dent->d_name, originalDent->d_name, nameLen); dent->d_name[nameLen] = 0; @@ -2598,6 +2649,7 @@ static struct { { HgfsServerQueryVolume, HGFS_SIZEOF_OP(HgfsRequestQueryVolumeV3) }, { HgfsServerSymlinkCreate, HGFS_SIZEOF_OP(HgfsRequestSymlinkCreateV3) }, { HgfsServerServerLockChange, sizeof (HgfsRequestServerLockChange) }, + { HgfsServerWriteWin32Stream, HGFS_SIZEOF_OP(HgfsRequestWriteWin32StreamV3) }, }; @@ -3283,67 +3335,6 @@ HgfsPackAndSendPacket(char *packet, // IN: packet to send } -/* - *----------------------------------------------------------------------------- - * - * HgfsServerCheckPathPrefix -- - * - * Given a path and a Hgfs host share path, check to see if the given - * share is a prefix of the path. - * - * Results: - * TRUE if share is a prefix of path. - * FALSE otherwise. - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ - -static Bool -HgfsServerCheckPathPrefix(const char *path, // IN: Path to check - const char *share, // IN: Prefix of path - size_t shareLen) // IN: Length of share -{ - ASSERT(path); - ASSERT(share); - - /* First make sure that share is a prefix of path. */ - if (strncmp(path, share, shareLen) != 0) { - return FALSE; - } - - /* - * Special case. The root share on Linux or Apple ("/") will not be followed - * by a second path separator. In this case, no additional checks besides the - * initial prefix check are needed. Just return success. - */ - - if (shareLen == 1 && *share == DIRSEPC) { - return TRUE; - } - - /* - * Now check to prevent false positives. In particular, consider the case - * where we have two shares: shareName and shareName1. - * Given the path /shareName1/test, the above check will allow through both - * shareName and shareName1. Check to make sure that the given share is - * a full path component. - */ - - if (*(path + shareLen) == DIRSEPC) { - return TRUE; - } - - if (*(path + shareLen) == '\0') { - return TRUE; - } - - return FALSE; -} - - /* *----------------------------------------------------------------------------- * @@ -3380,7 +3371,6 @@ HgfsInvalidateSessionObjects(DblLnkLst_Links *shares, // IN: List of new shares * Iterate over each node, skipping those that are unused. For each node, * if its filename is no longer within a share, remove it. */ - for (i = 0; i < session->numNodes; i++) { HgfsHandle handle; DblLnkLst_Links *l; @@ -3399,9 +3389,7 @@ HgfsInvalidateSessionObjects(DblLnkLst_Links *shares, // IN: List of new shares share = DblLnkLst_Container(l, HgfsSharedFolder, links); ASSERT(share); - if (HgfsServerCheckPathPrefix(session->nodeArray[i].utf8Name, - share->path, - share->pathLen)) { + if (strcmp(session->nodeArray[i].shareInfo.rootDir, share->path) == 0) { LOG(4, ("%s: Node is still valid\n", __FUNCTION__)); break; } @@ -3427,7 +3415,6 @@ HgfsInvalidateSessionObjects(DblLnkLst_Links *shares, // IN: List of new shares * Iterate over each search, skipping those that are on the free list. For * each search, if its base name is no longer within a share, remove it. */ - for (i = 0; i < session->numSearches; i++) { HgfsHandle handle; DblLnkLst_Links *l; @@ -3446,8 +3433,7 @@ HgfsInvalidateSessionObjects(DblLnkLst_Links *shares, // IN: List of new shares share = DblLnkLst_Container(l, HgfsSharedFolder, links); ASSERT(share); - if (HgfsServerCheckPathPrefix(session->searchArray[i].utf8Dir, - share->path, share->pathLen)) { + if (strcmp(session->searchArray[i].shareInfo.rootDir, share->path) == 0) { LOG(4, ("%s: Search is still valid\n", __FUNCTION__)); break; } @@ -3542,7 +3528,6 @@ HgfsServerStatFs(const char *pathName, // IN: Path we're interested in * delimiter on copy. Allow 0 length drives so that hidden feature "" can * work. */ - if (pathLength < 0 || pathLength >= sizeof p.mountPoint) { LOG(4, ("%s: could not get the volume name\n", __FUNCTION__)); @@ -3565,16 +3550,15 @@ HgfsServerStatFs(const char *pathName, // IN: Path we're interested in /* *----------------------------------------------------------------------------- * - * HgfsServerGetAccess -- + * HgfsServerGetShareInfo -- * - * Test a name for access permission and construct its local name - * if access is allowed. The name returned is allocated and must be - * freed by the caller. + * Construct local name based on the crossplatform CPName for the file. + * The name returned is allocated and must be freed by the caller. * * outLen can be NULL, in which case the length is not returned. * * Results: - * A status code indicating either success (access is allowed) or + * A status code indicating either success (correspondent share exists) or * a failure status. * * Side effects: @@ -3584,22 +3568,20 @@ HgfsServerStatFs(const char *pathName, // IN: Path we're interested in */ HgfsNameStatus -HgfsServerGetAccess(char *cpName, // IN: Cross-platform filename to check - size_t cpNameSize, // IN: Size of name cpName - HgfsOpenMode mode, // IN: Requested access mode - uint32 caseFlags, // IN: Case-sensitivity flags - char **bufOut, // OUT: File name in local fs - size_t *outLen) // OUT: Length of name out +HgfsServerGetShareInfo(char *cpName, // IN: Cross-platform filename to check + size_t cpNameSize, // IN: Size of name cpName + uint32 caseFlags, // IN: Case-sensitivity flags + HgfsShareInfo *shareInfo,// OUT: properties of the shared folder + char **bufOut, // OUT: File name in local fs + size_t *outLen) // OUT: Length of name out { HgfsNameStatus nameStatus; - char const *sharePath; char const *inEnd; char *next; char *myBufOut; char *convertedMyBufOut; char *out; size_t outSize; - size_t sharePathLen; /* Length of share's path */ size_t myBufOutLen; size_t convertedMyBufOutLen; int len; @@ -3631,14 +3613,16 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena } /* Check permission on the share and get the share path */ - nameStatus = HgfsServerPolicy_GetSharePath(cpName, len, mode, &sharePathLen, - &sharePath); + nameStatus = HgfsServerPolicy_ProcessCPName(cpName, + len, + &shareInfo->readPermissions, + &shareInfo->writePermissions, + &shareInfo->rootDir); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("%s: No such share (%s) or access denied\n", __FUNCTION__, - cpName)); - + LOG(4, ("%s: No such share (%s)\n", __FUNCTION__, cpName)); return nameStatus; } + shareInfo->rootDirLen = strlen(shareInfo->rootDir); /* Get the config options. */ nameStatus = HgfsServerPolicy_GetShareOptions(cpName, len, &shareOptions); @@ -3669,8 +3653,7 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena /* * See if we are dealing with a "root" share or regular share */ - - if (strlen(sharePath) == 0) { + if (shareInfo->rootDirLen == 0) { size_t prefixLen; /* @@ -3679,7 +3662,6 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena * buffer (for Win32) or simply get the prefix for root (for * linux). */ - tempSize = sizeof tempBuf; tempPtr = tempBuf; nameStatus = CPName_ConvertFromRoot((char const **) &cpName, @@ -3706,16 +3688,15 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena /* * This is a regular share. Append the path to the out buffer. */ - - if (outSize < sharePathLen + 1) { + if (outSize < shareInfo->rootDirLen + 1) { LOG(4, ("%s: share path too big\n", __FUNCTION__)); nameStatus = HGFS_NAME_STATUS_TOO_LONG; goto error; } - memcpy(out, sharePath, sharePathLen + 1); - out += sharePathLen; - outSize -= sharePathLen; + memcpy(out, shareInfo->rootDir, shareInfo->rootDirLen + 1); + out += shareInfo->rootDirLen; + outSize -= shareInfo->rootDirLen; } /* Convert the rest of the input name (if any) to a local name */ @@ -3788,8 +3769,8 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena if (!HgfsServerPolicy_IsShareOptionSet(shareOptions, HGFS_SHARE_HOST_DEFAULT_CASE) && HgfsServerCaseConversionRequired()) { - nameStatus = HgfsServerConvertCase(sharePath, sharePathLen, myBufOut, - myBufOutLen, caseFlags, + nameStatus = HgfsServerConvertCase(shareInfo->rootDir, shareInfo->rootDirLen, + myBufOut, myBufOutLen, caseFlags, &convertedMyBufOut, &convertedMyBufOutLen); @@ -3820,12 +3801,11 @@ HgfsServerGetAccess(char *cpName, // IN: Cross-platform filena * We should use the resolved file path for further file system * operations, instead of using the one passed from the client. */ - - nameStatus = HgfsServerHasSymlink(myBufOut, myBufOutLen, sharePath, - sharePathLen); + nameStatus = HgfsServerHasSymlink(myBufOut, myBufOutLen, shareInfo->rootDir, + shareInfo->rootDirLen); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("%s: parent path failed to be resolved: %d\n", __FUNCTION__, - nameStatus)); + LOG(4, ("%s: parent path failed to be resolved: %d\n", + __FUNCTION__, nameStatus)); goto error; } } @@ -3870,7 +3850,7 @@ error: * * This function assumes that CPName_GetComponent() will always succeed * with a size greater than 0, so it must ONLY be called after a call to - * HgfsServerGetAccess() that returns HGFS_NAME_STATUS_COMPLETE. + * HgfsServerGetShareInfo() that returns HGFS_NAME_STATUS_COMPLETE. * * Results: * True if it is a shared folder only, otherwise false @@ -4010,7 +3990,6 @@ HgfsServerGetDents(HgfsGetNameFunc getName, // IN: Function to get name * our purposes, so we use PATH_MAX as a reasonable upper bound on the * length of the name. */ - maxLen = PATH_MAX; #else maxLen = sizeof pDirEntry->d_name; @@ -4130,9 +4109,9 @@ error_free: HgfsInternalStatus HgfsServerSearchRealDir(char const *baseDir, // IN: Directory to search size_t baseDirLen, // IN: Length of directory - DirectorySearchType type, // IN: Kind of search char const *shareName, // IN: Share name containing the directory - HgfsSessionInfo *session, // IN: Share name containing the directory + char const *rootDir, // IN: Shared folder root directory + HgfsSessionInfo *session, // IN: Session info HgfsHandle *handle) // OUT: Search handle { HgfsSearch *search = NULL; @@ -4144,11 +4123,11 @@ HgfsServerSearchRealDir(char const *baseDir, // IN: Directory to search ASSERT(baseDir); ASSERT(handle); - ASSERT(type == DIRECTORY_SEARCH_TYPE_DIR); ASSERT(shareName); SyncMutex_Lock(&session->searchArrayLock); - search = HgfsAddNewSearch(baseDir, type, shareName, session); + search = HgfsAddNewSearch(baseDir, DIRECTORY_SEARCH_TYPE_DIR, shareName, + rootDir, session); if (!search) { LOG(4, ("%s: failed to get new search\n", __FUNCTION__)); status = HGFS_INTERNAL_STATUS_ERROR; @@ -4224,7 +4203,7 @@ HgfsServerSearchVirtualDir(HgfsGetNameFunc *getName, // IN: Name enumerator ASSERT(handle); SyncMutex_Lock(&session->searchArrayLock); - search = HgfsAddNewSearch("", type, "", session); + search = HgfsAddNewSearch("", type, "", "", session); if (!search) { LOG(4, ("%s: failed to get new search\n", __FUNCTION__)); status = HGFS_INTERNAL_STATUS_ERROR; @@ -4352,24 +4331,39 @@ HgfsRemoveLruNode(HgfsSessionInfo *session) // IN: session info ASSERT(session); ASSERT(session->numCachedOpenNodes > 0); - /* Remove the first item from the list that does not have a server lock. */ + /* + * Remove the first item from the list that does not have a server lock, + * file context or is open in sequential mode. + */ while (!found) { lruNode = DblLnkLst_Container(session->nodeCachedList.next, HgfsFileNode, links); ASSERT(lruNode->state == FILENODE_STATE_IN_USE_CACHED); - if (lruNode->serverLock != HGFS_LOCK_NONE) { - /* Move this node with the server lock to the beginning of the list. */ + if (lruNode->serverLock != HGFS_LOCK_NONE || lruNode->fileCtx != NULL + || (lruNode->flags & HGFS_FILE_NODE_SEQUENTIAL_FL) != 0) { + /* + * Move this node with the server lock to the beginning of the list. + * Also, prevent files opened in HGFS_FILE_NODE_SEQUENTIAL_FL mode + * from being closed. -- On some platforms, this mode does not + * allow files to be closed/re-opened (eg: When restoring a file + * into a Windows guest you cannot use BackupWrite, then close and + * re-open the file and continue to use BackupWrite. + */ DblLnkLst_Unlink1(&lruNode->links); DblLnkLst_LinkLast(&session->nodeCachedList, &lruNode->links); } else { found = TRUE; } } - handle = HgfsFileNode2Handle(lruNode); - if (!HgfsRemoveFromCacheInternal(handle, session)) { - LOG(4, ("%s: Could not remove the node from cache.\n", __FUNCTION__)); - + if (found) { + handle = HgfsFileNode2Handle(lruNode); + if (!HgfsRemoveFromCacheInternal(handle, session)) { + LOG(4, ("%s: Could not remove the node from cache.\n", __FUNCTION__)); + return FALSE; + } + } else { + LOG(4, ("%s: Could not find a node to remove from cache.\n", __FUNCTION__)); return FALSE; } @@ -4546,7 +4540,6 @@ HgfsUnpackOpenRequest(char const *packetIn, // IN: request packet * requestV3->fileName.length is user-provided, so this test must be * carefully written to prevent wraparounds. */ - if (requestV3->fileName.length > extra) { /* The input packet is smaller than the request. */ @@ -4558,12 +4551,11 @@ HgfsUnpackOpenRequest(char const *packetIn, // IN: request packet * garbage, but it's simpler to copy everything now and check the * valid bits before reading later. */ - openInfo->mask = requestV3->mask; openInfo->mode = requestV3->mode; openInfo->cpName = requestV3->fileName.name; openInfo->cpNameSize = requestV3->fileName.length; - openInfo->caseFlags = requestV3->fileName.caseType; + openInfo->caseFlags = requestV3->fileName.caseType; openInfo->flags = requestV3->flags; openInfo->specialPerms = requestV3->specialPerms; openInfo->ownerPerms = requestV3->ownerPerms; @@ -4595,7 +4587,6 @@ HgfsUnpackOpenRequest(char const *packetIn, // IN: request packet * requestV2->fileName.length is user-provided, so this test must be * carefully written to prevent wraparounds. */ - if (requestV2->fileName.length > extra) { /* The input packet is smaller than the request. */ return FALSE; @@ -4814,7 +4805,6 @@ HgfsUnpackDeleteRequest(char const *packetIn, // IN: request packet * If we've been asked to reuse a handle, we don't need to look at, let * alone test the filename or its length. */ - if (requestV3->fileName.flags & HGFS_FILE_NAME_USE_FILE_DESC) { *file = requestV3->fileName.fid; *cpName = NULL; @@ -4827,7 +4817,6 @@ HgfsUnpackDeleteRequest(char const *packetIn, // IN: request packet * request->fileName.length is user-provided, so this test must be * carefully written to prevent wraparounds. */ - if (requestV3->fileName.length > extra) { /* The input packet is smaller than the request */ @@ -4835,7 +4824,7 @@ HgfsUnpackDeleteRequest(char const *packetIn, // IN: request packet } *cpName = requestV3->fileName.name; *cpNameSize = requestV3->fileName.length; - *caseFlags = requestV3->fileName.caseType; + *caseFlags = requestV3->fileName.caseType; } break; } @@ -4866,7 +4855,6 @@ HgfsUnpackDeleteRequest(char const *packetIn, // IN: request packet * request->fileName.length is user-provided, so this test must be * carefully written to prevent wraparounds. */ - if (requestV2->fileName.length > extra) { /* The input packet is smaller than the request */ @@ -5059,7 +5047,6 @@ HgfsUnpackRenameRequest(char const *packetIn, // IN: request packet * alone test the filename or its length. This applies to the source * and the target. */ - if (requestV3->oldName.flags & HGFS_FILE_NAME_USE_FILE_DESC) { *srcFile = requestV3->oldName.fid; *cpOldName = NULL; @@ -5073,7 +5060,6 @@ HgfsUnpackRenameRequest(char const *packetIn, // IN: request packet * request->fileName.length is user-provided, so this test must be * carefully written to prevent wraparounds. */ - if (requestV3->oldName.length > extra) { /* The input packet is smaller than the request */ @@ -6470,6 +6456,137 @@ HgfsPackCreateDirReply(char const *packetIn, // IN: create dir operation ve } +/* + *----------------------------------------------------------------------------- + * + * HgfsUnpackWriteWin32StreamRequest -- + * + * Unpack hgfs SendFileUsingReader request. Returns file to write to, data + * and whether to restore the security stream. + * + * Results: + * TRUE on success. + * FALSE on failure. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +Bool +HgfsUnpackWriteWin32StreamRequest(char const *packetIn, // IN: incoming packet + size_t packetSize, // IN: size of packet + HgfsHandle *file, // OUT: file to write to + char **payload, // OUT: data to write + size_t *requiredSize, // OUT: size of data + Bool *doSecurity) // OUT: restore sec.str. +{ + HgfsRequest *request; + size_t extra; + + ASSERT(packetIn); + ASSERT(file); + ASSERT(payload); + ASSERT(requiredSize); + ASSERT(doSecurity); + + request = (HgfsRequest *)packetIn; + + switch (request->op) { + case HGFS_OP_WRITE_WIN32_STREAM_V3: + { + HgfsRequestWriteWin32StreamV3 *requestV3 = + (HgfsRequestWriteWin32StreamV3 *)HGFS_REQ_GET_PAYLOAD_V3(packetIn); + + /* Enforced by the dispatch function */ + ASSERT(packetSize >= HGFS_REQ_PAYLOAD_SIZE_V3(request) - 1); + extra = packetSize - HGFS_REQ_PAYLOAD_SIZE_V3(request) + 1; + + *file = requestV3->file; + *payload = requestV3->payload; + *requiredSize = requestV3->requiredSize; + *doSecurity = (requestV3->flags & HGFS_WIN32_STREAM_IGNORE_SECURITY) == 0; + + /* + * requiredSize is user-provided, so this test must be carefully + * written to prevent wraparounds. + */ + if (*requiredSize > extra) { + /* + * The driver wants to write more bytes than there is in its payload. + * Truncate the request. + */ + + *requiredSize = extra; + } + + break; + } + default: + return FALSE; + } + + return TRUE; +} + + +/* + *----------------------------------------------------------------------------- + * + * HgfsPackWriteWin32StreamReply -- + * + * Pack hgfs SendFileUsingReader reply. + * Returns the actual amount of data written in the reply. + * + * Results: + * TRUE if valid op and reply set, FALSE otherwise. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +Bool +HgfsPackWriteWin32StreamReply(char const *packetIn, // IN: incoming packet + HgfsInternalStatus status, // IN: reply status + uint32 actualSize, // IN: amount written + char **packetOut, // OUT: outgoing packet + size_t *packetSize) // OUT: size of packet +{ + HgfsRequest *header = (HgfsRequest *)packetIn; + + ASSERT(packetIn); + ASSERT(packetOut); + ASSERT(packetSize); + + *packetOut = NULL; + *packetSize = 0; + + switch (header->op) { + case HGFS_OP_WRITE_WIN32_STREAM_V3: { + HgfsReplyWriteWin32StreamV3 *reply; + + *packetSize = HGFS_REP_PAYLOAD_SIZE_V3(reply); + *packetOut = Util_SafeMalloc(*packetSize); + ((HgfsReply *)*packetOut)->id = header->id; + ((HgfsReply *)*packetOut)->status = HgfsConvertFromInternalStatus(status); + + reply = (HgfsReplyWriteWin32StreamV3 *)HGFS_REP_GET_PAYLOAD_V3(*packetOut); + reply->actualSize = actualSize; + reply->reserved = 0; + break; + } + default: + return FALSE; + } + + return TRUE; +} + + + /* *----------------------------------------------------------------------------- * @@ -6529,7 +6646,6 @@ HgfsBuildRelativePath(const char* source, // IN: source file name * Find out how many directories deep the source file is from the common * part of the path. */ - while(*relativeSource != '\0') { sourceSep = strchr(relativeSource, DIRSEPC); if (sourceSep != NULL) { @@ -6553,8 +6669,7 @@ HgfsBuildRelativePath(const char* source, // IN: source file name * to the relative target path. */ - targetSize = level * HGFS_PARENT_DIR_LEN + strlen(relativeTarget) + - sizeof '\0'; + targetSize = level * HGFS_PARENT_DIR_LEN + strlen(relativeTarget) + sizeof '\0'; result = malloc(targetSize); currentPosition = result; if (result != NULL) { @@ -6563,10 +6678,8 @@ HgfsBuildRelativePath(const char* source, // IN: source file name level--; currentPosition += HGFS_PARENT_DIR_LEN; } - memcpy(currentPosition, relativeTarget, strlen(relativeTarget) + - sizeof '\0'); + memcpy(currentPosition, relativeTarget, strlen(relativeTarget) + sizeof '\0'); } - return result; } @@ -6651,7 +6764,6 @@ HgfsServerOplockBreakReply(const unsigned char *packetIn, // IN: Reply packet * is double checked in HgfsAckOplockBreak, so we'd be safe from a garbage * value. */ - HgfsAckOplockBreak(lockData, reply->serverLock); } diff --git a/open-vm-tools/lib/hgfsServer/hgfsServerInt.h b/open-vm-tools/lib/hgfsServer/hgfsServerInt.h index 96f45f1a6..ef46d2934 100644 --- a/open-vm-tools/lib/hgfsServer/hgfsServerInt.h +++ b/open-vm-tools/lib/hgfsServer/hgfsServerInt.h @@ -127,6 +127,20 @@ typedef enum { # define HGFS_DEFAULT_SHARE_ACCESS 0 #endif // _WIN32 +typedef struct HgfsShareInfo { + /* Filename of the root directory for the shared folder */ + const char *rootDir; + + /* Length of the root directory filename (does not include nul terminator) */ + size_t rootDirLen; + + /* Read permissions for the shared folder, needed for handle => name conversions. */ + Bool readPermissions; + + /* Write permissions for the shared folder, needed for handle => name conversions. */ + Bool writePermissions; +} HgfsShareInfo; + /* * This struct represents a file on the local filesystem that has been * opened by a remote client. We store the name of the local file and @@ -178,6 +192,17 @@ typedef struct HgfsFileNode { /* File flags - see below. */ uint32 flags; + + /* + * Context as required by some file operations. Eg: BackupWrite on + * Windows: BackupWrite requires the caller to hold on to a pointer + * to a Windows internal data structure between subsequent calls to + * BackupWrite while restoring a file. + */ + void *fileCtx; + + /* Parameters associated with the share. */ + HgfsShareInfo shareInfo; } HgfsFileNode; @@ -228,6 +253,9 @@ typedef struct HgfsSearch { * when we want to retrieve the attributes for each dent. */ DirectorySearchType type; + + /* Parameters associated with the share. */ + HgfsShareInfo shareInfo; } HgfsSearch; /* HgfsSessionInfo flags. */ @@ -339,6 +367,7 @@ typedef struct HgfsFileOpenInfo { char *cpName; char *utf8Name; uint32 caseFlags; /* Case-sensitivity flags. */ + HgfsShareInfo shareInfo; /* Parameters associated with the share. */ } HgfsFileOpenInfo; typedef struct HgfsFileAttrInfo { @@ -431,6 +460,14 @@ HgfsServerGetAccess(char *in, // IN: CP filename to check char **bufOut, // OUT: File name in local fs size_t *outLen); // OUT: Length of name out +HgfsNameStatus +HgfsServerGetShareInfo(char *cpName, // IN: Cross-platform filename to check + size_t cpNameSize, // IN: Size of name cpName + uint32 caseFlags, // IN: Case-sensitivity flags + HgfsShareInfo* shareInfo,// OUT: Shared folder properties + char **bufOut, // OUT: File name in local fs + size_t *outLen); // OUT: Length of name out + Bool HgfsServerIsSharedFolderOnly(char const *in, // IN: CP filename to check size_t inSize); // IN: Size of name in @@ -445,8 +482,8 @@ HgfsServerScandir(char const *baseDir, // IN: Directory to search in HgfsInternalStatus HgfsServerSearchRealDir(char const *baseDir, // IN: Directory to search size_t baseDirLen, // IN: Length of directory - DirectorySearchType type, // IN: Kind of search char const *shareName, // IN: Share name + char const *rootDir, // IN: Root directory for the share HgfsSessionInfo *session, // IN: Session info HgfsHandle *handle); // OUT: Search handle @@ -532,6 +569,11 @@ HgfsServerServerLockChange(char const *packetIn, // IN: incoming packet size_t packetSize, // IN: size of packet HgfsSessionInfo *session); // IN: opaque transport data +HgfsInternalStatus +HgfsServerWriteWin32Stream(char const *packetIn, // IN: incoming packet + size_t packetSize, // IN: size of packet + HgfsSessionInfo *session); // IN: opaque transport data + /* Unpack/pack requests/reply helper functions. */ Bool @@ -643,6 +685,21 @@ HgfsPackCreateDirReply(char const *packetIn, // IN: incoming packet char **packetOut, // OUT: outgoing packet size_t *packetSize); // OUT: size of packet +Bool +HgfsUnpackWriteWin32StreamRequest(char const *packetIn, // IN: incoming packet + size_t packetSize, // IN: size of packet + HgfsHandle *file, // OUT: file to write to + char **payload, // OUT: data to write + size_t *requiredSize, // OUT: size of data + Bool *doSecurity); // OUT: restore sec.str. + +Bool +HgfsPackWriteWin32StreamReply(char const *packetIn, // IN: incoming packet + HgfsInternalStatus status, // IN: reply status + uint32 actualSize, // IN: amount written + char **packetOut, // OUT: outgoing packet + size_t *packetSize); // OUT: size of packet + /* Node cache functions. */ Bool @@ -663,7 +720,8 @@ HgfsIsServerLockAllowed(HgfsSessionInfo *session); // IN: session info Bool HgfsHandle2FileDesc(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: session info - fileDesc *fd); // OUT: OS handle (file descriptor) + fileDesc *fd, // OUT: OS handle (file descriptor) + void **fileCtx); // OUT: OS file context Bool HgfsFileDesc2Handle(fileDesc fd, // IN: OS handle (file descriptor) @@ -680,7 +738,13 @@ HgfsHandle2FileName(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: session info char **fileName, // OUT: CP file name size_t *fileNameSize); // OUT: CP file name size - +Bool +HgfsHandle2FileNameMode(HgfsHandle handle, // IN: Hgfs file handle + HgfsSessionInfo *session,// IN: Session info + Bool *readPermissions, // OUT: shared folder permissions + Bool *writePermissions, // OUT: shared folder permissions + char **fileName, // OUT: UTF8 file name + size_t *fileNameSize); // OUT: UTF8 file name size Bool HgfsHandle2AppendFlag(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: session info @@ -699,7 +763,8 @@ HgfsHandle2ServerLock(HgfsHandle handle, // IN: Hgfs file handle Bool HgfsUpdateNodeFileDesc(HgfsHandle handle, // IN: Hgfs file handle HgfsSessionInfo *session, // IN: session info - fileDesc fd); // OUT: OS handle (file desc + fileDesc fd, // IN: OS handle (file desc + void *fileCtx); // IN: OS file context Bool HgfsUpdateNodeServerLock(fileDesc fd, // IN: OS handle @@ -738,7 +803,8 @@ HgfsGetSearchCopy(HgfsHandle handle, // IN: Hgfs search handle HgfsSearch *copy); // IN/OUT: Copy of the search HgfsInternalStatus -HgfsCloseFile(fileDesc fileDesc); // IN: OS handle of the file +HgfsCloseFile(fileDesc fileDesc, // IN: OS handle of the file + void *fileCtx); // IN: file context Bool HgfsServerGetOpenMode(HgfsFileOpenInfo *openInfo, // IN: Open info to examine diff --git a/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c b/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c index 9f8ff106d..8049cf9e4 100644 --- a/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c +++ b/open-vm-tools/lib/hgfsServer/hgfsServerLinux.c @@ -280,6 +280,9 @@ static HgfsInternalStatus HgfsGetattrFromName(char *fileName, char *shareName, HgfsFileAttrInfo *attr, char **targetName); +static HgfsInternalStatus HgfsAccess(char *fileName, + char *shareName, + size_t shareNameLen); static HgfsInternalStatus HgfsGetattrFromFd(int fd, HgfsSessionInfo *session, @@ -394,7 +397,6 @@ HgfsServerSigOplockBreak(int sigNum, // IN: Signal number * We've got all we need from the signal handler, let it continue handling * signals of this type. */ - Sig_Continue(sigNum); /* @@ -402,7 +404,6 @@ HgfsServerSigOplockBreak(int sigNum, // IN: Signal number * break is pending will return the new lease we should use. It'll be * F_RDLCK if we can downgrade, or F_UNLCK if we should break altogether. */ - newLease = fcntl(fd, F_GETLEASE); if (newLease == F_RDLCK) { newServerLock = HGFS_LOCK_SHARED; @@ -426,7 +427,6 @@ HgfsServerSigOplockBreak(int sigNum, // IN: Signal number * the acknowledgement, and firing the platform-specific acknowledgement * function (where we'll downgrade the lease). */ - lockData = malloc(sizeof *lockData); if (lockData) { lockData->fileDesc = fd; @@ -716,7 +716,7 @@ HgfsServerGetOpenMode(HgfsFileOpenInfo *openInfo, // IN: Open info to examine * * HgfsCloseFile -- * - * Closes the file descriptor. + * Closes the file descriptor and release the file context. * * Results: * Zero on success. @@ -729,14 +729,14 @@ HgfsServerGetOpenMode(HgfsFileOpenInfo *openInfo, // IN: Open info to examine */ HgfsInternalStatus -HgfsCloseFile(fileDesc fileDesc) // IN: File descriptor +HgfsCloseFile(fileDesc fileDesc, // IN: File descriptor + void *fileCtx) // IN: File context { if (close(fileDesc) != 0) { int error = errno; LOG(4, ("%s: Could not close fd %d: %s\n", __FUNCTION__, fileDesc, strerror(error))); - return error; } @@ -781,7 +781,6 @@ HgfsCheckFileNode(char const *localName, // IN LOG(4, ("%s: couldn't stat local file \"%s\": %s\n", __FUNCTION__, localName, strerror(error))); - return error; } @@ -839,7 +838,6 @@ HgfsGetFd(HgfsHandle hgfsHandle, // IN: HGFS file handle * path. Unfortuntely, even the fast path may need to look at the node's * append flag. */ - node.utf8Name = NULL; if (!HgfsGetNodeCopy(hgfsHandle, session, TRUE, &node)) { /* XXX: Technically, this can also fail if we're out of memory. */ @@ -855,9 +853,8 @@ HgfsGetFd(HgfsHandle hgfsHandle, // IN: HGFS file handle * in append mode. If not, close the file and reopen it in append * mode. */ - if (append && !(node.flags & HGFS_FILE_NODE_APPEND_FL)) { - status = HgfsCloseFile(node.fileDesc); + status = HgfsCloseFile(node.fileDesc, node.fileCtx); if (status != 0) { LOG(4, ("%s: Couldn't close file \"%s\" for reopening\n", __FUNCTION__, node.utf8Name)); @@ -868,7 +865,6 @@ HgfsGetFd(HgfsHandle hgfsHandle, // IN: HGFS file handle * Update the node in the cache with the new value of the append * flag. */ - if (!HgfsUpdateNodeAppendFlag(hgfsHandle, session, TRUE)) { LOG(4, ("%s: Could not update the node in the cache\n", __FUNCTION__)); @@ -886,7 +882,6 @@ HgfsGetFd(HgfsHandle hgfsHandle, // IN: HGFS file handle * reopening. This means we need to open a file. But first, verify * that the file we intend to open isn't stale. */ - status = HgfsCheckFileNode(node.utf8Name, &node.localId); if (status != 0) { goto exit; @@ -896,7 +891,6 @@ HgfsGetFd(HgfsHandle hgfsHandle, // IN: HGFS file handle * We're not interested in creating a new file. So let's just get the * flags for a simple open request. This really should always work. */ - HgfsServerGetOpenFlags(0, &openFlags); /* @@ -905,7 +899,6 @@ HgfsGetFd(HgfsHandle hgfsHandle, // IN: HGFS file handle * * XXX: We should use O_LARGEFILE, see lib/file/fileIOPosix.c --hpreg */ - newFd = Posix_Open(node.utf8Name, node.mode | openFlags | (append ? O_APPEND : 0)); @@ -922,8 +915,7 @@ HgfsGetFd(HgfsHandle hgfsHandle, // IN: HGFS file handle * Update the original node with the new value of the file desc. * This call might fail if the node is not used anymore. */ - - if (!HgfsUpdateNodeFileDesc(hgfsHandle, session, newFd)) { + if (!HgfsUpdateNodeFileDesc(hgfsHandle, session, newFd, NULL)) { LOG(4, ("%s: Could not update the node -- node is not used.\n", __FUNCTION__)); status = EBADF; @@ -942,7 +934,6 @@ HgfsGetFd(HgfsHandle hgfsHandle, // IN: HGFS file handle *fd = newFd; } free(node.utf8Name); - return status; } @@ -1029,6 +1020,57 @@ HgfsValidateOpen(HgfsFileOpenInfo *openInfo, // IN: Open info struct openFlags &= ~O_NOFOLLOW; } + /* + * Need to validate that open does not change the file for read + * only shared folders. + */ + status = 0; + if (!openInfo->shareInfo.writePermissions) { + if ((openFlags & (O_APPEND | O_CREAT | O_TRUNC)) || + (openMode & (O_WRONLY | O_RDWR))) { + status = access(openInfo->utf8Name, F_OK); + if (status < 0) { + status = errno; + if (status == ENOENT && (openFlags & O_CREAT) != 0) { + status = EACCES; + } + } else { + /* + * Handle the case when the file already exists: + * If there is an attempt to createa new file, fail with "EEXIST" + * error, otherwise set error to "EACCES". + */ + if ((openFlags & O_CREAT) && (openFlags & O_EXCL)) { + status = EEXIST; + } else { + status = EACCES; + } + } + } + if (status != 0) { + goto exit; + } + } + + if (!openInfo->shareInfo.readPermissions) { + /* + * "Drop Box" / "FTP incoming" type of shared folders. + * Allow creating a new file. Deny opening exisitng file. + */ + status = access(openInfo->utf8Name, F_OK); + if (status < 0) { + status = errno; + if (status != ENOENT || (openFlags & O_CREAT) == 0) { + status = EACCES; + } + } else { + status = EACCES; + } + if (status != 0) { + goto exit; + } + } + /* * Determine if hidden attribute needs to be updated. * It needs to be updated if a new file is created or an existing file is truncated. @@ -1041,7 +1083,7 @@ HgfsValidateOpen(HgfsFileOpenInfo *openInfo, // IN: Open info struct ((openFlags & O_CREAT) && (openFlags & O_EXCL))) { needToSetAttribute = TRUE; } else if (openFlags & O_CREAT) { - int err = access(openInfo->utf8Name, F_OK); + int err = Posix_Access(openInfo->utf8Name, F_OK); needToSetAttribute = (err != 0) && (errno == ENOENT); } } @@ -1149,7 +1191,6 @@ HgfsAcquireServerLock(fileDesc fileDesc, // IN: OS handle * * XXX: Do I need to do fcntl(fileDesc, F_SETOWN, getpid())? */ - if (fcntl(fileDesc, F_SETSIG, SIGIO)) { error = errno; Log("%s: Could not set SIGIO as the desired lease break signal for " @@ -1162,7 +1203,6 @@ HgfsAcquireServerLock(fileDesc fileDesc, // IN: OS handle * If the client just wanted the best lock possible, start off with a write * lease and move down to a read lease if that was unavailable. */ - if ((desiredLock == HGFS_LOCK_OPPORTUNISTIC) || (desiredLock == HGFS_LOCK_EXCLUSIVE)) { leaseType = F_WRLCK; @@ -1179,7 +1219,6 @@ HgfsAcquireServerLock(fileDesc fileDesc, // IN: OS handle * someone else is already writing or reading to the file, try again with * a read lease. */ - if (desiredLock == HGFS_LOCK_OPPORTUNISTIC && (errno == EAGAIN || errno == EACCES)) { leaseType = F_RDLCK; @@ -1203,7 +1242,6 @@ HgfsAcquireServerLock(fileDesc fileDesc, // IN: OS handle /* Got a lease of some kind. */ LOG(4, ("%s: Got %s lease for fd %d\n", __FUNCTION__, leaseType == F_WRLCK ? "write" : "read", fileDesc)); - *serverLock = leaseType == F_WRLCK ? HGFS_LOCK_EXCLUSIVE : HGFS_LOCK_SHARED; return TRUE; #else @@ -1261,14 +1299,12 @@ HgfsGetattrResolveAlias(char const *fileName, // IN: Input filename * symlinks to symlinks. If the file is an alias, wasAliased will be set to * TRUE and fileRef will reference the target file. */ - osStatus = FSPathMakeRef(fileName, &fileRef, NULL); if (osStatus != noErr) { LOG(4, ("%s: could not create file reference: error %d\n", __FUNCTION__, (int32)osStatus)); goto exit; } - /* * If alias points to an unmounted volume, the volume needs to be explicitly * mounted on the host. Mount flag kResolveAliasFileNoUI serves the purpose. @@ -1282,7 +1318,6 @@ HgfsGetattrResolveAlias(char const *fileName, // IN: Input filename * (HgfsGetattrFromName) will assume that an error means the file is a * regular file. */ - osStatus = FSResolveAliasFileWithMountFlags(&fileRef, FALSE, &targetIsFolder, &wasAliased, kResolveAliasFileNoUI); @@ -1305,7 +1340,6 @@ HgfsGetattrResolveAlias(char const *fileName, // IN: Input filename * and convert the CFURL to a basic UTF-8 string using a call to * CFURLGetFileSystemRepresentation(). */ - resolvedRef = CFURLCreateFromFSRef(NULL, &fileRef); if (resolvedRef == NULL) { LOG(4, ("%s: could not create resolved URL reference from " @@ -1348,7 +1382,6 @@ HgfsGetattrResolveAlias(char const *fileName, // IN: Input filename if (resolvedRef != NULL) { CFRelease(resolvedRef); } - return status; #endif } @@ -1459,7 +1492,7 @@ HgfsConvertComponentCase(char *currentComponent, // IN ASSERT(convertedComponentSize); /* Open the specified directory. */ - dir = opendir(dirPath); + dir = Posix_OpenDir(dirPath); if (!dir) { ret = errno; goto exit; @@ -1508,7 +1541,6 @@ HgfsConvertComponentCase(char *currentComponent, // IN * The current directory entry is a case insensitive match to * the specified component. Malloc and copy the current directory entry. */ - myConvertedComponentSize = dentryNameLen + 1; myConvertedComponent = malloc(myConvertedComponentSize); if (myConvertedComponent == NULL) { @@ -1577,7 +1609,6 @@ HgfsConstructConvertedPath(char **path, // IN/OUT if (!p) { int error = errno; LOG(4, ("%s: failed to realloc.\n", __FUNCTION__)); - return error; } @@ -1587,7 +1618,6 @@ HgfsConstructConvertedPath(char **path, // IN/OUT /* Copy out the converted component to curDir, and free it. */ Str_Strncat(p, *pathSize, DIRSEPS, sizeof (DIRSEPS)); Str_Strncat(p, *pathSize, convertedPath, convertedPathLen); - return 0; } @@ -1653,7 +1683,6 @@ HgfsCaseInsensitiveLookup(const char *sharePath, // IN } else { *convertedFileNameLength = strlen(fileName); } - return 0; } @@ -1804,10 +1833,9 @@ HgfsServerConvertCase(const char *sharePath, // IN */ if (caseFlags == HGFS_FILE_NAME_CASE_INSENSITIVE && - access(fileName, F_OK) == -1) { + Posix_Access(fileName, F_OK) == -1) { LOG(4, ("%s: Case insensitive lookup, fileName: %s, flags: %u.\n", __FUNCTION__, fileName, caseFlags)); - error = HgfsCaseInsensitiveLookup(sharePath, sharePathLength, fileName, fileNameLength, convertedFileName, @@ -1817,8 +1845,13 @@ HgfsServerConvertCase(const char *sharePath, // IN * Success or non-ENOENT error code. HgfsCaseInsensitiveLookup can * return ENOENT, and its ok to continue if it is ENOENT. */ - switch (error) { + /* + * Both ENOENT and 0 mean that HgfsCaseInsensitiveLookup + * successfully built the converted name thus we return + * HGFS_NAME_STATUS_COMPLETE in these two cases. + */ + case 0: case ENOENT: nameStatus = HGFS_NAME_STATUS_COMPLETE; break; @@ -1829,7 +1862,6 @@ HgfsServerConvertCase(const char *sharePath, // IN nameStatus = HGFS_NAME_STATUS_FAILURE; break; } - return nameStatus; } @@ -1840,7 +1872,6 @@ HgfsServerConvertCase(const char *sharePath, // IN } else { *convertedFileNameLength = fileNameLength; } - return nameStatus; } @@ -1891,13 +1922,13 @@ HgfsEffectivePermissions(char *fileName, // IN: Input filename uint32 *permissions) // OUT: Effective permissions { *permissions = 0; - if (access(fileName, R_OK) == 0) { + if (Posix_Access(fileName, R_OK) == 0) { *permissions |= HGFS_PERM_READ; } - if (access(fileName, X_OK) == 0) { + if (Posix_Access(fileName, X_OK) == 0) { *permissions |= HGFS_PERM_EXEC; } - if (!readOnlyShare && (access(fileName, W_OK) == 0)) { + if (!readOnlyShare && (Posix_Access(fileName, W_OK) == 0)) { *permissions |= HGFS_PERM_WRITE; } return 0; @@ -2170,7 +2201,6 @@ HgfsGetattrFromName(char *fileName, // IN/OUT: Input filenam * regular files, directories, and symlinks. On Mac OS, we'll additionally * treat finder aliases as symlinks. */ - if (S_ISDIR(stats.st_mode)) { attr->type = HGFS_FILE_TYPE_DIRECTORY; LOG(4, ("%s: is a directory\n", __FUNCTION__)); @@ -2182,7 +2212,6 @@ HgfsGetattrFromName(char *fileName, // IN/OUT: Input filenam * In the case of a symlink, we should populate targetName if the * caller asked. Use st_size and readlink() to do so. */ - if (targetName != NULL) { myTargetName = Posix_ReadLink(fileName); @@ -2196,7 +2225,6 @@ HgfsGetattrFromName(char *fileName, // IN/OUT: Input filenam * not have read the entire link. If that happens, just return * "out of memory". */ - status = error ? error : ENOMEM; goto exit; } @@ -2229,7 +2257,6 @@ HgfsGetattrFromName(char *fileName, // IN/OUT: Input filenam * outside the shared folder then treat it the same way as if alias * has not been resolved. */ - HgfsNameStatus nameStatus; size_t sharePathLen; const char* sharePath; @@ -2252,7 +2279,6 @@ HgfsGetattrFromName(char *fileName, // IN/OUT: Input filenam * the length of the target name (not including the * nul-terminator), and the permissions should be 777. */ - stats.st_size = strlen(myTargetName); stats.st_mode |= ACCESSPERMS; attr->type = HGFS_FILE_TYPE_SYMLINK; @@ -2317,6 +2343,49 @@ exit: } +/* + *----------------------------------------------------------------------------- + * + * HgfsAccess -- + * + * Check is a file with the given name exists and accessible, error code + * otherwise. + * The function does not follow symlinks unless HGFS_SHARE_FOLLOW_SYMLINKS + * flag is specified for the shared folder. + * + * Results: + * Zero on success. + * Non-zero on failure. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static HgfsInternalStatus +HgfsAccess(char *fileName, // IN: local file path + char *shareName, // IN: Name of the share + size_t shareNameLen) // IN: Length of the share name +{ + HgfsFileAttrInfo attr; + HgfsShareOptions configOptions; + HgfsNameStatus nameStatus; + HgfsInternalStatus status; + + /* Get the config options. */ + nameStatus = HgfsServerPolicy_GetShareOptions(shareName, shareNameLen, + &configOptions); + if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { + LOG(4, ("%s: no matching share: %s.\n", __FUNCTION__, shareName)); + status = ENOENT; + } else { + status = HgfsGetattrFromName(fileName, configOptions, shareName, + &attr, NULL); + } + return status; +} + /* *----------------------------------------------------------------------------- * @@ -2366,7 +2435,6 @@ HgfsGetattrFromFd(int fd, // IN: file descriptor * For now, everything that isn't a directory or symlink is a regular * file. */ - if (S_ISDIR(stats.st_mode)) { attr->type = HGFS_FILE_TYPE_DIRECTORY; LOG(4, ("%s: is a directory\n", __FUNCTION__)); @@ -2414,7 +2482,6 @@ HgfsGetattrFromFd(int fd, // IN: file descriptor * In the case we have a Windows client, force the hidden flag. * This will be ignored by Linux, Solaris clients. */ - HgfsGetHiddenAttr(fileName, attr); if (shareMode == HGFS_OPEN_MODE_READ_ONLY) { @@ -2422,7 +2489,6 @@ HgfsGetattrFromFd(int fd, // IN: file descriptor * Share does not allow write, so tell the client * everything is read only. */ - if (attr->mask & HGFS_ATTR_VALID_OWNER_PERMS) { attr->ownerPerms &= ~HGFS_PERM_WRITE; } @@ -2436,7 +2502,6 @@ HgfsGetattrFromFd(int fd, // IN: file descriptor exit: free(fileName); - return status; } @@ -2723,7 +2788,6 @@ HgfsSetattrTimes(struct stat *statBuf, // IN: stat info * the guest time, and alwaysUseHostTime will be TRUE if the config * option to always use host time is set. */ - if (attr->mask & HGFS_ATTR_VALID_ACCESS_TIME) { if (!alwaysUseHostTime && (hints & HGFS_ATTR_HINT_SET_ACCESS_TIME)) { /* Use the guest-provided time */ @@ -2858,7 +2922,6 @@ HgfsSetattrFromFd(HgfsHandle file, // IN: file descriptor * toggle permsChanged since it should not influence our decision of * whether to actually call chmod or not. */ - permsChanged = HgfsSetattrMode(&statBuf, attr, &newPermissions); if (permsChanged) { LOG(4, ("%s: set mode %o\n", __FUNCTION__, (unsigned)newPermissions)); @@ -2890,7 +2953,6 @@ HgfsSetattrFromFd(HgfsHandle file, // IN: file descriptor * the truncate request. At this point, the server must safeguard itself * against deadlock. */ - if (!HgfsHandle2ServerLock(file, session, &serverLock)) { LOG(4, ("%s: File handle is no longer valid.\n", __FUNCTION__)); status = EBADF; @@ -2997,10 +3059,15 @@ HgfsSetattrFromName(char *cpName, // IN: Name Bool idChanged = FALSE; HgfsServerLock serverLock; HgfsShareOptions configOptions; - - nameStatus = HgfsServerGetAccess(cpName, cpNameSize, - HGFS_OPEN_MODE_WRITE_ONLY, caseFlags, - &localName, NULL); + size_t localNameLen; + HgfsShareInfo shareInfo; + + nameStatus = HgfsServerGetShareInfo(cpName, + cpNameSize, + caseFlags, + &shareInfo, + &localName, + &localNameLen); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { LOG(4, ("%s: access check failed\n", __FUNCTION__)); status = HgfsConvertFromNameStatus(nameStatus); @@ -3028,7 +3095,6 @@ HgfsSetattrFromName(char *cpName, // IN: Name * XXX: This is racy. But clients interested in preventing a race should * have sent us a Setattr packet with a valid HGFS handle. */ - if (File_IsSymLink(localName)) { LOG(4, ("%s: pathname contains a symlink\n", __FUNCTION__)); status = EINVAL; @@ -3047,6 +3113,13 @@ HgfsSetattrFromName(char *cpName, // IN: Name goto exit_free; } + if (!HgfsServerPolicy_CheckMode(HGFS_OPEN_MODE_WRITE_ONLY, + shareInfo.writePermissions, + shareInfo.readPermissions)) { + status = EACCES; + goto exit_free; + } + /* * Try to make each requested attribute change. In the event that * one operation fails, we still attempt to perform any other @@ -3060,7 +3133,6 @@ HgfsSetattrFromName(char *cpName, // IN: Name * toggle permsChanged since it should not influence our decision of * whether to actually call chmod or not. */ - permsChanged = HgfsSetattrMode(&statBuf, attr, &newPermissions); if (permsChanged) { LOG(4, ("%s: set mode %o\n", __FUNCTION__, (unsigned)newPermissions)); @@ -3074,12 +3146,10 @@ HgfsSetattrFromName(char *cpName, // IN: Name } idChanged = HgfsSetattrOwnership(attr, &newUid, &newGid); - /* * Chown changes the uid and gid together. If one of them should * not be changed, we pass in -1. */ - if (idChanged) { if (Posix_Lchown(localName, newUid, newGid) < 0) { error = errno; @@ -3096,7 +3166,6 @@ HgfsSetattrFromName(char *cpName, // IN: Name * the truncate request. At this point, the server must safeguard itself * against deadlock. */ - if (HgfsFileHasServerLock(localName, session, &serverLock, &fd)) { LOG(4, ("%s: Client attempted to truncate an oplocked file\n", __FUNCTION__)); @@ -3135,7 +3204,6 @@ HgfsSetattrFromName(char *cpName, // IN: Name exit_free: free(localName); - exit: return status; } @@ -3222,7 +3290,6 @@ HgfsServerScandir(char const *baseDir, // IN: Directory to search in * Allocate the new dent and set it up. We do a straight memcpy of * the entire record to avoid dealing with platform-specific fields. */ - myDents[myNumDents] = malloc(newDent->d_reclen); if (myDents[myNumDents] == NULL) { status = ENOMEM; @@ -3257,7 +3324,6 @@ HgfsServerScandir(char const *baseDir, // IN: Directory to search in * On error, free all allocated dents. On success, set the dents pointer * given to us by the client. */ - if (status != 0) { size_t i; for (i = 0; i < myNumDents; i++) { @@ -3348,6 +3414,7 @@ HgfsServerOpen(char const *packetIn, // IN: incoming packet char *packetOut; size_t packetOutSize; HgfsOpenFlags savedOpenFlags = 0; + size_t localNameLen; ASSERT(packetIn); ASSERT(session); @@ -3364,9 +3431,12 @@ HgfsServerOpen(char const *packetIn, // IN: incoming packet goto exit; } - nameStatus = HgfsServerGetAccess(openInfo.cpName, openInfo.cpNameSize, - openInfo.mode, openInfo.caseFlags, - &localName, NULL); + nameStatus = HgfsServerGetShareInfo(openInfo.cpName, + openInfo.cpNameSize, + openInfo.caseFlags, + &openInfo.shareInfo, + &localName, + &localNameLen); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { LOG(4, ("%s: access check failed\n", __FUNCTION__)); status = HgfsConvertFromNameStatus(nameStatus); @@ -3413,7 +3483,6 @@ HgfsServerOpen(char const *packetIn, // IN: incoming packet * since that won't break a shared oplock, but the clients should already * realize that the second open can be avoided via sharing handles, too. */ - if (HgfsFileHasServerLock(localName, session, &serverLock, &newFd)) { LOG (4, ("%s: Client tried to open new handle for oplocked file %s.\n", __FUNCTION__, localName)); @@ -3562,13 +3631,11 @@ HgfsServerRead(char const *packetIn, // IN: incoming packet * requiredSize is user-provided, so this test must be carefully * written to prevent wraparounds. */ - if (requiredSize > extra) { /* * The client wants to read more bytes than our payload can handle. * Truncate the request */ - requiredSize = extra; } @@ -3587,14 +3654,12 @@ HgfsServerRead(char const *packetIn, // IN: incoming packet if (status != 0) { LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__)); free(packetOut); - return status; } if (!HgfsHandleIsSequentialOpen(file, session, &sequentialOpen)) { LOG(4, ("%s: Could not get sequenial open status\n", __FUNCTION__)); free(packetOut); - return EBADF; } @@ -3610,7 +3675,6 @@ HgfsServerRead(char const *packetIn, // IN: incoming packet * Seek to the offset and read from the file. Grab the IO lock to make * this and the subsequent read atomic. */ - SyncMutex_Lock(&session->fileIOLock); if (!sequentialOpen) { # ifdef linux @@ -3756,14 +3820,12 @@ HgfsServerWrite(char const *packetIn, // IN: incoming packet if (status != 0) { LOG(4, ("%s: Could not get file descriptor\n", __FUNCTION__)); free(packetOut); - return status; } if (!HgfsHandleIsSequentialOpen(file, session, &sequentialOpen)) { LOG(4, ("%s: Could not get sequential open status\n", __FUNCTION__)); free(packetOut); - return EBADF; } @@ -3771,13 +3833,11 @@ HgfsServerWrite(char const *packetIn, // IN: incoming packet * requiredSize is user-provided, so this test must be carefully * written to prevent wraparounds. */ - if (requiredSize > extra) { /* * The driver wants to write more bytes than there is in its payload. * Truncate the request */ - requiredSize = extra; } @@ -3878,6 +3938,7 @@ HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet HgfsCaseType caseFlags = HGFS_FILE_NAME_DEFAULT_CASE; size_t replySize; char *packetOut; + HgfsShareInfo shareInfo; ASSERT(packetIn); ASSERT(session); @@ -3922,17 +3983,19 @@ HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet * request->dirName.length is user-provided, so this test must be carefully * written to prevent wraparounds. */ - if (dirNameLength > extra) { /* The input packet is smaller than the request */ status = EPROTO; goto exit; } - /* It is now safe to read the dirName */ - nameStatus = HgfsServerGetAccess(dirName, dirNameLength, - HGFS_OPEN_MODE_READ_ONLY, - caseFlags, &baseDir, &baseDirLen); + /* It is now safe to read the file name. */ + nameStatus = HgfsServerGetShareInfo(dirName, + dirNameLength, + caseFlags, + &shareInfo, + &baseDir, + &baseDirLen); switch (nameStatus) { case HGFS_NAME_STATUS_COMPLETE: { @@ -3967,9 +4030,19 @@ HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet LOG(4, ("%s: dirName: %s.\n", __FUNCTION__, dirName)); status = HgfsServerSearchRealDir(baseDir, baseDirLen, - DIRECTORY_SEARCH_TYPE_DIR, - dirName, session, &handle); + dirName, + shareInfo.rootDir, + session, + &handle); free(baseDir); + /* + * If the directory exists but shared folder is write only + * then return access denied, otherwise preserve the original + * error code. + */ + if (!shareInfo.readPermissions && HGFS_NAME_STATUS_COMPLETE == status) { + status = HGFS_NAME_STATUS_ACCESS_DENIED; + } if (status != 0) { LOG(4, ("%s: couldn't scandir\n", __FUNCTION__)); goto exit; @@ -4010,7 +4083,6 @@ HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet * Return handle to the search object as the reply to the search * open. */ - *replySearch = handle; if (!HgfsPackAndSendPacket(packetOut, replySize, 0, header->id, @@ -4022,7 +4094,6 @@ HgfsServerSearchOpen(char const *packetIn, // IN: incoming packet exit: free(packetOut); - return status; } @@ -4086,7 +4157,6 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet search.utf8ShareName)); free(search.utf8Dir); free(search.utf8ShareName); - return ENOENT; } } @@ -4112,7 +4182,6 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet * Construct the UTF8 version of the full path to the file, and call * HgfsGetattrFromName to get the attributes of the file. */ - fullNameLen = search.utf8DirLen + 1 + length; fullName = (char *)malloc(fullNameLen + 1); if (!fullName) { @@ -4121,7 +4190,6 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet free(search.utf8Dir); free(search.utf8ShareName); free(dent); - return ENOMEM; } memcpy(fullName, search.utf8Dir, search.utf8DirLen); @@ -4174,7 +4242,6 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet * share gets resolved into its full path, and gets its attributes * via HgfsGetattrFromName. */ - if (strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { LOG(4, ("%s: assigning %s default attributes\n", @@ -4192,7 +4259,6 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet free(dent); free(search.utf8Dir); free(search.utf8ShareName); - return HgfsConvertFromNameStatus(nameStatus); } @@ -4202,7 +4268,6 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet * problems on the host, the server still enumerates it and * returns to the client. */ - status = HgfsGetattrFromName(sharePath, configOptions, dent->d_name, &attr, NULL); if (status != 0) { @@ -4218,7 +4283,6 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet * No conversion needed on OS X because dent->d_name is the shareName * that was converted to normal form C in hgfsServerPolicyHost. */ - entryName = dent->d_name; entryNameLen = length; break; @@ -4228,7 +4292,6 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet * The POSIX implementation of HgfsSearchOpen could not have created * this kind of search. */ - NOT_IMPLEMENTED(); break; default: @@ -4244,7 +4307,6 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet /* * We need to unescape the name before sending it back to the client */ - entryNameLen = HgfsEscape_Undo(entryName, entryNameLen + 1); /* @@ -4254,7 +4316,6 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet * one with success. Now we return an error. This may be a non-issue * since what filesystems allow dent lengths as high as 6144 bytes? */ - status = 0; if (!HgfsPackSearchReadReply(packetIn, status, entryName, entryNameLen, &attr, &packetOut, &packetOutSize)) { @@ -4286,7 +4347,6 @@ HgfsServerSearchRead(char const *packetIn, // IN: incoming packet !HgfsPacketSend(packetOut, packetOutSize, session, 0)) { free(packetOut); } - return status; } @@ -4327,6 +4387,8 @@ HgfsServerGetattr(char const *packetIn, // IN: incoming packet HgfsShareOptions configOptions; char *packetOut; size_t packetOutSize; + size_t localNameLen; + HgfsShareInfo shareInfo; ASSERT(packetIn); ASSERT(session); @@ -4354,10 +4416,12 @@ HgfsServerGetattr(char const *packetIn, // IN: incoming packet * Depending on whether this file/dir is real or virtual, either * forge its attributes or look them up in the actual filesystem. */ - - nameStatus = HgfsServerGetAccess(cpName, cpNameSize, - HGFS_OPEN_MODE_READ_ONLY, - caseFlags, &localName, NULL); + nameStatus = HgfsServerGetShareInfo(cpName, + cpNameSize, + caseFlags, + &shareInfo, + &localName, + &localNameLen); switch (nameStatus) { case HGFS_NAME_STATUS_INCOMPLETE_BASE: @@ -4387,7 +4451,12 @@ HgfsServerGetattr(char const *packetIn, // IN: incoming packet status = HgfsGetattrFromName(localName, configOptions, cpName, &attr, &targetName); free(localName); - if (status != 0) { + if (status == 0 && + !HgfsServerPolicy_CheckMode(HGFS_OPEN_MODE_READ_ONLY, + shareInfo.writePermissions, + shareInfo.readPermissions)) { + status = EACCES; + } else if (status != 0) { /* * If it is a dangling share server should not return ENOENT * to the client because it causes confusion: a name that is returned @@ -4457,6 +4526,8 @@ HgfsServerSetattr(char const *packetIn, // IN: incoming packet ASSERT(packetIn); ASSERT(session); + LOG(4, ("NEW LIB! HgfsServerSetAttr Called!\n")); + if (!HgfsUnpackSetattrRequest(packetIn, packetSize, &attr, &hints, &cpName, &cpNameSize, &file, &caseFlags)) { status = EPROTO; @@ -4515,6 +4586,8 @@ HgfsServerCreateDir(char const *packetIn, // IN: incoming packet mode_t permissions; char *packetOut; size_t packetOutSize; + size_t localNameLen; + HgfsShareInfo shareInfo; ASSERT(packetIn); ASSERT(session); @@ -4523,9 +4596,12 @@ HgfsServerCreateDir(char const *packetIn, // IN: incoming packet return EPROTO; } - nameStatus = HgfsServerGetAccess(info.cpName, info.cpNameSize, - HGFS_OPEN_MODE_WRITE_ONLY, - info.caseFlags, &localName, NULL); + nameStatus = HgfsServerGetShareInfo(info.cpName, + info.cpNameSize, + info.caseFlags, + &shareInfo, + &localName, + &localNameLen); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { LOG(4, ("%s: access check failed\n", __FUNCTION__)); @@ -4534,6 +4610,25 @@ HgfsServerCreateDir(char const *packetIn, // IN: incoming packet ASSERT(localName); + /* + * For read-only shares we must never attempt to create a directory. + * However the error code must be different depending on the existence + * of the file or directory with the same name. + */ + if (!shareInfo.writePermissions) { + int error = HgfsAccess(localName, info.cpName, info.cpNameSize); + if (error != 0) { + if (error == ENOENT) { + error = EACCES; + } + } else { + error = EEXIST; + } + LOG(4, ("HgfsServerCreateDir: failed access check, error %d\n", error)); + free(localName); + return error; + } + /* * Create mode_t for use in mkdir(). If owner permissions are missing, use * read/write/execute for the owner permissions. If group or other @@ -4544,7 +4639,6 @@ HgfsServerCreateDir(char const *packetIn, // IN: incoming packet * a directory requires a valid mode, it's highly unlikely that we'll ever * be creating a directory without owner permissions. */ - permissions = ~ALLPERMS; permissions |= info.mask & HGFS_CREATE_DIR_VALID_SPECIAL_PERMS ? info.specialPerms << 9 : 0; @@ -4565,7 +4659,6 @@ HgfsServerCreateDir(char const *packetIn, // IN: incoming packet * Set hidden attribute when requested. * Do not fail directory creation if setting hidden attribute fails. */ - HgfsSetHiddenXAttr(localName, TRUE); } @@ -4620,6 +4713,8 @@ HgfsServerDeleteFile(char const *packetIn, // IN: incoming packet uint32 caseFlags; char *packetOut; size_t packetOutSize; + size_t localNameLen; + HgfsShareInfo shareInfo; ASSERT(packetIn); ASSERT(session); @@ -4630,18 +4725,21 @@ HgfsServerDeleteFile(char const *packetIn, // IN: incoming packet } if (hints & HGFS_DELETE_HINT_USE_FILE_DESC) { - if (!HgfsHandle2FileName(file, session, &cpName, &cpNameSize)) { + if (!HgfsHandle2FileNameMode(file, session, &shareInfo.writePermissions, + &shareInfo.readPermissions, &cpName, &cpNameSize)) { LOG(4, ("%s: could not map cached file handle %u\n", __FUNCTION__, file)); - return EBADF; } localName = cpName; } else { - nameStatus = HgfsServerGetAccess(cpName, cpNameSize, - HGFS_OPEN_MODE_WRITE_ONLY, caseFlags, - &localName, NULL); + nameStatus = HgfsServerGetShareInfo(cpName, + cpNameSize, + caseFlags, + &shareInfo, + &localName, + &localNameLen); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { LOG(4, ("%s: access check failed\n", __FUNCTION__)); @@ -4651,6 +4749,21 @@ HgfsServerDeleteFile(char const *packetIn, // IN: incoming packet ASSERT(localName); + /* + * Deleting a file needs both read and write permssions. + * However the error code must be different depending on the existence + * of the file with the same name. + */ + if (!shareInfo.writePermissions || !shareInfo.readPermissions) { + int error = HgfsAccess(localName, cpName, cpNameSize); + if (error == 0) { + error = EACCES; + } + LOG(4, ("HgfsServerDeleteFile: failed access check, error %d\n", error)); + free(localName); + return error; + } + LOG(4, ("%s: unlinking \"%s\"\n", __FUNCTION__, localName)); error = Posix_Unlink(localName); free(localName); @@ -4705,6 +4818,8 @@ HgfsServerDeleteDir(char const *packetIn, // IN: incoming packet uint32 caseFlags; char *packetOut; size_t packetOutSize; + size_t localNameLen; + HgfsShareInfo shareInfo; ASSERT(packetIn); ASSERT(session); @@ -4715,18 +4830,21 @@ HgfsServerDeleteDir(char const *packetIn, // IN: incoming packet } if (hints & HGFS_DELETE_HINT_USE_FILE_DESC) { - if (!HgfsHandle2FileName(file, session, &cpName, &cpNameSize)) { + if (!HgfsHandle2FileNameMode(file, session, &shareInfo.writePermissions, + &shareInfo.readPermissions, &cpName, &cpNameSize)) { LOG(4, ("%s: could not map cached file handle %u\n", __FUNCTION__, file)); - return EBADF; } localName = cpName; } else { - nameStatus = HgfsServerGetAccess(cpName, cpNameSize, - HGFS_OPEN_MODE_WRITE_ONLY, - caseFlags, &localName, NULL); + nameStatus = HgfsServerGetShareInfo(cpName, + cpNameSize, + caseFlags, + &shareInfo, + &localName, + &localNameLen); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { LOG(4, ("%s: access check failed\n", __FUNCTION__)); @@ -4741,6 +4859,21 @@ HgfsServerDeleteDir(char const *packetIn, // IN: incoming packet return EPERM; } + /* + * Deleting a directory needs both read and write permssions. + * However the error code must be different depending on the existence + * of the file with the same name. + */ + if (!shareInfo.writePermissions || !shareInfo.readPermissions) { + int error = HgfsAccess(localName, cpName, cpNameSize); + if (error == 0) { + error = EACCES; + } + LOG(4, ("HgfsServerDeleteDir: failed access check, error %d\n", error)); + free(localName); + return error; + } + ASSERT(localName); LOG(4, ("%s: removing \"%s\"\n", __FUNCTION__, localName)); @@ -4759,7 +4892,6 @@ HgfsServerDeleteDir(char const *packetIn, // IN: incoming packet if (!HgfsPacketSend(packetOut, packetOutSize, session, 0)) { free(packetOut); } - return 0; } @@ -4791,7 +4923,9 @@ HgfsServerRename(char const *packetIn, // IN: incoming packet { HgfsNameStatus nameStatus; char *localOldName = NULL; + size_t localOldNameLen; char *localNewName = NULL; + size_t localNewNameLen; char *cpOldName; uint32 cpOldNameLen; char *cpNewName; @@ -4806,6 +4940,7 @@ HgfsServerRename(char const *packetIn, // IN: incoming packet uint32 newCaseFlags = 0; char *packetOut; size_t packetOutSize; + HgfsShareInfo shareInfo; ASSERT(packetIn); ASSERT(session); @@ -4819,11 +4954,11 @@ HgfsServerRename(char const *packetIn, // IN: incoming packet if (hints & HGFS_RENAME_HINT_USE_SRCFILE_DESC) { size_t localOldNameLen; - if (!HgfsHandle2FileName(srcFile, session, &localOldName, - &localOldNameLen)) { + if (!HgfsHandle2FileNameMode(srcFile, session, &shareInfo.writePermissions, + &shareInfo.readPermissions, &localOldName, + &localOldNameLen)) { LOG(4, ("%s: could not map cached source file handle %u\n", __FUNCTION__, srcFile)); - return EBADF; } @@ -4837,12 +4972,13 @@ HgfsServerRename(char const *packetIn, // IN: incoming packet } else { - nameStatus = HgfsServerGetAccess(cpOldName, cpOldNameLen, - HGFS_OPEN_MODE_READ_WRITE, - oldCaseFlags, &localOldName, NULL); + nameStatus = HgfsServerGetShareInfo(cpOldName, + cpOldNameLen, + oldCaseFlags, + &shareInfo, + &localOldName, + &localOldNameLen); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { - LOG(4, ("%s: old name access check failed\n", __FUNCTION__)); - return HgfsConvertFromNameStatus(nameStatus); } @@ -4854,16 +4990,30 @@ HgfsServerRename(char const *packetIn, // IN: incoming packet status = EPERM; goto exit; } + + /* + * Renaming a file requires both read and write permissions for the original file. + * However the error code must be different depending on the existence + * of the file with the same name. + */ + if (!shareInfo.writePermissions || !shareInfo.readPermissions) { + status = HgfsAccess(localOldName, cpOldName, cpOldNameLen); + if (status == 0) { + status = EACCES; + } + LOG(4, ("HgfsServerRename: failed access check, error %d\n", status)); + goto exit; + } } if (hints & HGFS_RENAME_HINT_USE_TARGETFILE_DESC) { size_t localNewNameLen; - if (!HgfsHandle2FileName(targetFile, session, &localNewName, - &localNewNameLen)) { + if (!HgfsHandle2FileNameMode(targetFile, session, &shareInfo.writePermissions, + &shareInfo.readPermissions, &localNewName, + &localNewNameLen)) { LOG(4, ("%s: could not map cached target file handle %u\n", __FUNCTION__, targetFile)); - return EBADF; } @@ -4877,9 +5027,12 @@ HgfsServerRename(char const *packetIn, // IN: incoming packet } else { - nameStatus = HgfsServerGetAccess(cpNewName, cpNewNameLen, - HGFS_OPEN_MODE_WRITE_ONLY, - newCaseFlags, &localNewName, NULL); + nameStatus = HgfsServerGetShareInfo(cpNewName, + cpNewNameLen, + newCaseFlags, + &shareInfo, + &localNewName, + &localNewNameLen); if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { LOG(4, ("%s: new name access check failed\n", __FUNCTION__)); status = HgfsConvertFromNameStatus(nameStatus); @@ -4917,6 +5070,20 @@ HgfsServerRename(char const *packetIn, // IN: incoming packet } } + /* + * Renaming a file requires both read and write permssions for the target file. + * However the error code must be different depending on the existence + * of the file with the same name. + */ + if (!shareInfo.writePermissions || !shareInfo.readPermissions) { + status = HgfsAccess(localNewName, cpNewName, cpNewNameLen); + if (status == 0 || status == ENOENT) { + status = EACCES; + } + LOG(4, ("HgfsServerRename: failed access check, error %d\n", status)); + goto exit; + } + LOG(4, ("%s: renaming \"%s\" to \"%s\"\n", __FUNCTION__, localOldName, localNewName)); error = Posix_Rename(localOldName, localNewName); @@ -4933,7 +5100,6 @@ HgfsServerRename(char const *packetIn, // IN: incoming packet * XXX: Note that this operation can fail (out of memory), but we'd like * the client to see success anyway, because the rename succeeded. */ - status = 0; HgfsUpdateNodeNames(localOldName, localNewName, session); if (!HgfsPackRenameReply(packetIn, status, &packetOut, &packetOutSize)) { @@ -5005,6 +5171,7 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet uint64 *totalBytes; char *packetOut; size_t packetOutSize; + HgfsShareInfo shareInfo; ASSERT(packetIn); ASSERT(session); @@ -5024,7 +5191,6 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet * We don't yet support file handle for this operation. * Clients should retry using the file name. */ - if (requestV3->fileName.flags & HGFS_FILE_NAME_USE_FILE_DESC) { LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__)); status = EPARAMETERNOTSUPPORTED; @@ -5066,7 +5232,6 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet * request->fileName.length is user-provided, so this test must be carefully * written to prevent wraparounds. */ - if (fileNameLength > extra) { /* The input packet is smaller than the request. */ status = EPROTO; @@ -5074,9 +5239,12 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet } /* It is now safe to read the file name field. */ - nameStatus = HgfsServerGetAccess(fileName, fileNameLength, - HGFS_OPEN_MODE_READ_WRITE, - caseFlags, &utf8Name, &utf8NameLen); + nameStatus = HgfsServerGetShareInfo(fileName, + fileNameLength, + caseFlags, + &shareInfo, + &utf8Name, + &utf8NameLen); switch (nameStatus) { case HGFS_NAME_STATUS_INCOMPLETE_BASE: /* @@ -5116,7 +5284,6 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet * Now go through all shares and get share paths on the server. * Then retrieve space info for each share's volume. */ - offset = 0; while ((dent = HgfsGetSearchResult(handle, session, offset, TRUE)) != NULL) { @@ -5133,7 +5300,6 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet * need to make sure to handle them properly. In particular, they * should be ignored within QueryVolume, as they're not real shares. */ - if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) { LOG(4, ("%s: Skipping fake share %s\n", __FUNCTION__, dent->d_name)); @@ -5145,7 +5311,6 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet * The above check ignores '.' and '..' so we do not include them in * the share count here. */ - shares++; /* @@ -5185,7 +5350,6 @@ HgfsServerQueryVolume(char const *packetIn, // IN: incoming packet * Pick the drive with amount of space available and return that * according to different volume info type. */ - switch (infoType) { case VOLUME_INFO_TYPE_MIN: if ((outFreeBytes > freeBytes) || firstShare) { @@ -5279,6 +5443,8 @@ HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet char *packetOut; size_t packetOutSize; HgfsInternalStatus status = 0; + size_t localSymlinkNameLen; + HgfsShareInfo shareInfo; ASSERT(packetIn); ASSERT(session); @@ -5303,7 +5469,6 @@ HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet * targetName starts after symlinkName + the variable length array * in symlinkName. */ - targetNameP = (HgfsFileNameV3 *)(symlinkName + 1 + symlinkNameLength); targetName = targetNameP->name; targetNameLength = targetNameP->length; @@ -5312,7 +5477,6 @@ HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet * We don't yet support file handle for this operation. * Clients should retry using the file name. */ - if (requestV3->symlinkName.flags & HGFS_FILE_NAME_USE_FILE_DESC || targetNameP->flags & HGFS_FILE_NAME_USE_FILE_DESC) { LOG(4, ("%s: Doesn't support file handle.\n", __FUNCTION__)); @@ -5364,17 +5528,33 @@ HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet * "targetName" field */ - nameStatus = HgfsServerGetAccess(symlinkName, symlinkNameLength, - HGFS_OPEN_MODE_READ_WRITE, - caseFlags, &localSymlinkName, - NULL); - if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { + nameStatus = HgfsServerGetShareInfo(symlinkName, + symlinkNameLength, + caseFlags, + &shareInfo, + &localSymlinkName, + &localSymlinkNameLen); + if (nameStatus != HGFS_NAME_STATUS_COMPLETE) { LOG(4, ("%s: symlink name access check failed\n", __FUNCTION__)); status = HgfsConvertFromNameStatus(nameStatus); goto exit; } + if (!shareInfo.writePermissions ) { + int error = HgfsAccess(localSymlinkName, symlinkName, symlinkNameLength); + if (error != 0) { + if (error == ENOENT) { + error = EACCES; + } + } else { + error = EEXIST; + } + LOG(4, ("HgfsServerCreateDir: failed access check, error %d\n", error)); + free(localSymlinkName); + return error; + } + ASSERT(localSymlinkName); extra -= symlinkNameLength; @@ -5382,7 +5562,6 @@ HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet * targetNameLength is user-provided, so this test must be carefully * written to prevent wraparounds. */ - if (targetNameLength > extra) { /* The input packet is smaller than the request */ free(localSymlinkName); @@ -5430,12 +5609,10 @@ HgfsServerSymlinkCreate(char const *packetIn, // IN: incoming packet session, 0)) { goto exit; } - return status; exit: free(packetOut); - return status; } @@ -5509,7 +5686,6 @@ HgfsServerHasSymlink(const char *fileName, // IN * access to entire host) or * - fileName and sharePath are same. */ - if (fileNameLength == 0 || sharePathLength == 0 || Str_Strcmp(sharePath, fileName) == 0) { @@ -5518,14 +5694,12 @@ HgfsServerHasSymlink(const char *fileName, // IN /* Separate out parent directory of the fileName. */ File_GetPathName(fileName, &fileDirName, NULL); - /* * File_GetPathName may return an empty string to signify the root of * the filesystem. To simplify subsequent processing, let's convert such * empty strings to "/" when found. See File_GetPathName header comment * for details. */ - if (strlen(fileDirName) == 0) { char *p; p = realloc(fileDirName, sizeof (DIRSEPS)); @@ -5543,7 +5717,6 @@ HgfsServerHasSymlink(const char *fileName, // IN * Resolve parent directory of fileName. * Use realpath(2) to resolve the parent. */ - resolvedFileDirPath = Posix_RealPath(fileDirName); if (resolvedFileDirPath == NULL) { /* Let's return some meaningful errors if possible. */ @@ -5575,11 +5748,35 @@ HgfsServerHasSymlink(const char *fileName, // IN exit: free(resolvedFileDirPath); free(fileDirName); - return nameStatus; } +/* + *----------------------------------------------------------------------------- + * + * HgfsServerWriteWin32Stream -- + * + * Handle a write request in the WIN32_STREAM_ID format. + * + * Results: + * EOPNOTSUPP, because this is unimplemented. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +HgfsInternalStatus +HgfsServerWriteWin32Stream(char const *packetIn, // IN: incoming packet + size_t packetSize, // IN: size of packet + HgfsSessionInfo *session) // IN: session info +{ + return EOPNOTSUPP; +} + + /* *----------------------------------------------------------------------------- * @@ -5645,7 +5842,6 @@ HgfsAckOplockBreak(ServerLockData *lockData, // IN: server lock info * lock if our previous call to fcntl() said we could, and if the client * wants to downgrade to a shared lock. Otherwise, we break altogether. */ - if (lockData->serverLock == HGFS_LOCK_SHARED && replyLock == HGFS_LOCK_SHARED) { newLock = F_RDLCK; @@ -5756,7 +5952,6 @@ HgfsGetHiddenXAttr(char const *fileName, // IN: File name } else { LOG(4, ("%s: Error %d when getting attributes\n", __FUNCTION__, err)); } - return err; } diff --git a/open-vm-tools/lib/hgfsServerPolicyGuest/hgfsServerPolicyGuest.c b/open-vm-tools/lib/hgfsServerPolicyGuest/hgfsServerPolicyGuest.c index bf1e5a2a7..79d74e96c 100644 --- a/open-vm-tools/lib/hgfsServerPolicyGuest/hgfsServerPolicyGuest.c +++ b/open-vm-tools/lib/hgfsServerPolicyGuest/hgfsServerPolicyGuest.c @@ -481,6 +481,51 @@ HgfsServerPolicy_GetSharePath(char const *nameIn, // IN: Name to check } +/* + *----------------------------------------------------------------------------- + * + * HgfsServerPolicy_ProcessCPName -- + * + * Get the local path for a share name by looking at the requested + * name, finding the matching share (if any) and returning the share's + * local path local path and permissions. + * + * Results: + * An HgfsNameStatus value indicating the result is returned. + * + * The local path for the shareName is also returned if a match is found. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +HgfsNameStatus +HgfsServerPolicy_ProcessCPName(char const *nameIn, // IN: name in CPName form + size_t nameInLen, // IN: length of the name + Bool *readAccess, // OUT: Read permissions + Bool *writeAccess, // OUT: Write permissions + char const **shareBaseDir) // OUT: Shared directory +{ + HgfsSharedFolder *myShare; + + ASSERT(nameIn); + ASSERT(shareBaseDir); + + myShare = HgfsServerPolicyGetShare(&myState, nameIn, nameInLen); + if (!myShare) { + LOG(4, ("%s: No matching share name\n", __FUNCTION__)); + return HGFS_NAME_STATUS_DOES_NOT_EXIST; + } + + *readAccess = myShare->readAccess; + *writeAccess = myShare->writeAccess; + *shareBaseDir = myShare->path; + return HGFS_NAME_STATUS_COMPLETE; +} + + /* *----------------------------------------------------------------------------- * @@ -608,3 +653,62 @@ HgfsServerPolicy_GetShareMode(char const *nameIn, // IN: Share name to re return HGFS_NAME_STATUS_COMPLETE; } + + +/* + *----------------------------------------------------------------------------- + * + * HgfsServerPolicy_CheckMode -- + * + * Checks if the requested mode may be granted depending on read/write permissions. + * + * Results: + * TRUE if the requested mode can be granted, FALSE otherwise. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +Bool +HgfsServerPolicy_CheckMode(HgfsOpenMode mode, // IN: mode to check + Bool writePermissions, // IN: callers write permissions + Bool readPermissions) // IN: callers read permissions +{ + /* + * See if access is allowed in the requested mode. + * + * XXX Yeah, this is retarded. We should be using bits instead of + * an enum for HgfsOpenMode. Add it to the todo list. [bac] + */ + switch (HGFS_OPEN_MODE_ACCMODE(mode)) { + case HGFS_OPEN_MODE_READ_ONLY: + if (!readPermissions) { + LOG(4, ("HgfsServerPolicyCheckMode: Read access denied\n")); + return FALSE; + } + break; + + case HGFS_OPEN_MODE_WRITE_ONLY: + if (!writePermissions) { + LOG(4, ("HgfsServerPolicyCheckMode: Write access denied\n")); + return FALSE; + } + break; + + case HGFS_OPEN_MODE_READ_WRITE: + if (!readPermissions || !writePermissions) { + LOG(4, ("HgfsServerPolicyCheckMode: Read/write access denied\n")); + return FALSE; + } + break; + + default: + LOG(0, ("HgfsServerPolicyCheckMode: Invalid mode\n")); + ASSERT(FALSE); + return FALSE; + } + + return TRUE; +} diff --git a/open-vm-tools/lib/image/imageUtilPng.c b/open-vm-tools/lib/image/imageUtilPng.c index 9a67e824b..60dae4c4a 100644 --- a/open-vm-tools/lib/image/imageUtilPng.c +++ b/open-vm-tools/lib/image/imageUtilPng.c @@ -282,31 +282,6 @@ ImageUtilDataWriteCallback(png_structp png_ptr, // IN * * ImageUtil_ConstructPNGBuffer -- * - * Writes a PNG of the image to the DynBuf passed in. - * - * Results: - * TRUE if successful, FALSE otherwise. - * - * Side effects: - * If successful, imageData should be destroyed. - * - *---------------------------------------------------------------------------- - */ - -Bool -ImageUtil_ConstructPNGBuffer(const ImageInfo *image, // IN - DynBuf *imageData) // OUT - -{ - return ImageUtil_ConstructPNGBufferEx(image, NULL, imageData); -} - - -/* - *---------------------------------------------------------------------------- - * - * ImageUtil_ConstructPNGBufferEx -- - * * Writes a PNG of the image to the DynBuf passed in. Accepts a zlib * compression level (0-9, 0 means no compression, -1 means "use the * default"). @@ -321,9 +296,9 @@ ImageUtil_ConstructPNGBuffer(const ImageInfo *image, // IN */ Bool -ImageUtil_ConstructPNGBufferEx(const ImageInfo *image, // IN - const ImagePngWriteOptions *pOptions, // IN/OPT - DynBuf *imageData) // OUT +ImageUtil_ConstructPNGBuffer(const ImageInfo *image, // IN + const ImagePngWriteOptions *pOptions, // IN/OPT + DynBuf *imageData) // OUT { png_structp png_ptr; png_infop info_ptr; diff --git a/open-vm-tools/lib/include/appUtil.h b/open-vm-tools/lib/include/appUtil.h index 0595eae1e..12e7a4103 100644 --- a/open-vm-tools/lib/include/appUtil.h +++ b/open-vm-tools/lib/include/appUtil.h @@ -105,9 +105,8 @@ AppUtil_GetIconIndexAndLocationForShortcut(const TCHAR *shortcut, }; #endif // __cplusplus -#endif //_WIN32 +#else // not _WIN32 -#if defined(linux) #include void AppUtil_Init(void); diff --git a/open-vm-tools/lib/include/buildNumber.h b/open-vm-tools/lib/include/buildNumber.h index 8500c6adf..a14e56b16 100644 --- a/open-vm-tools/lib/include/buildNumber.h +++ b/open-vm-tools/lib/include/buildNumber.h @@ -1,12 +1,12 @@ #define BUILD_NUMBER \ - "build-179896" + "build-187411" #define BUILD_NUMBER_NUMERIC \ - 179896 + 187411 #define BUILD_NUMBER_NUMERIC_STRING \ - "179896" + "187411" #define PRODUCT_BUILD_NUMBER \ - "product-build-620" + "product-build-653" #define PRODUCT_BUILD_NUMBER_NUMERIC \ - 620 + 653 #define PRODUCT_BUILD_NUMBER_NUMERIC_STRING \ - "620" + "653" diff --git a/open-vm-tools/lib/include/community_source.h b/open-vm-tools/lib/include/community_source.h new file mode 100644 index 000000000..4923270e0 --- /dev/null +++ b/open-vm-tools/lib/include/community_source.h @@ -0,0 +1,74 @@ +/********************************************************* + * Copyright (C) 2009 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. + * + *********************************************************/ + +/********************************************************* + * The contents of this file are subject to the terms of the Common + * Development and Distribution License (the "License") version 1.0 + * and no later version. You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at + * http://www.opensource.org/licenses/cddl1.php + * + * See the License for the specific language governing permissions + * and limitations under the License. + * + *********************************************************/ + +/* + * community_source.h -- + * + * Macros for excluding source code from community. + */ + +#ifndef _COMMUNITY_SOURCE_H_ +#define _COMMUNITY_SOURCE_H_ + +#define INCLUDE_ALLOW_USERLEVEL +#define INCLUDE_ALLOW_VMMEXT +#define INCLUDE_ALLOW_MODULE +#define INCLUDE_ALLOW_VMMON +#define INCLUDE_ALLOW_VMNIXMOD +#define INCLUDE_ALLOW_VMKERNEL +#define INCLUDE_ALLOW_VMKDRIVERS +#define INCLUDE_ALLOW_VMK_MODULE +#define INCLUDE_ALLOW_DISTRIBUTE +#define INCLUDE_ALLOW_VMCORE +#define INCLUDE_ALLOW_VMIROM +#include "includeCheck.h" + +/* + * Convenience macro for COMMUNITY_SOURCE + */ +#undef EXCLUDE_COMMUNITY_SOURCE +#ifdef COMMUNITY_SOURCE + #define EXCLUDE_COMMUNITY_SOURCE(x) +#else + #define EXCLUDE_COMMUNITY_SOURCE(x) x +#endif + +#undef COMMUNITY_SOURCE_INTEL_SECRET +#if !defined(COMMUNITY_SOURCE) || defined(INTEL_SOURCE) +/* + * It's ok to include INTEL_SECRET source code for non-commsrc, + * or for drops directed at Intel. + */ + #define COMMUNITY_SOURCE_INTEL_SECRET +#endif + +#endif diff --git a/open-vm-tools/lib/include/file.h b/open-vm-tools/lib/include/file.h index 5b89098ca..35b01b3e2 100644 --- a/open-vm-tools/lib/include/file.h +++ b/open-vm-tools/lib/include/file.h @@ -297,8 +297,6 @@ EXTERN Bool File_MakeCfgFileExecutable(ConstUnicode pathName); EXTERN char *File_ExpandAndCheckDir(const char *dirName); -EXTERN Bool File_SupportsPrealloc(const char *file); - #ifdef __cplusplus } // extern "C" { #endif diff --git a/open-vm-tools/lib/include/fileIO.h b/open-vm-tools/lib/include/fileIO.h index 4998d886c..d23272734 100644 --- a/open-vm-tools/lib/include/fileIO.h +++ b/open-vm-tools/lib/include/fileIO.h @@ -417,4 +417,6 @@ EXTERN Bool FileIO_SetExcludedFromTimeMachine(char const *pathName, Bool isExcluded); #endif +Bool FileIO_SupportsPrealloc(const char *pathName, Bool fsCheck); + #endif // _FILEIO_H_ diff --git a/open-vm-tools/lib/include/guestCaps.h b/open-vm-tools/lib/include/guestCaps.h index 608624c0f..7a90b45d6 100644 --- a/open-vm-tools/lib/include/guestCaps.h +++ b/open-vm-tools/lib/include/guestCaps.h @@ -66,6 +66,7 @@ typedef enum { GHI_CAP_TRAY_ICONS = 19, // supports ghi.guest.trayIcon commands GHI_CAP_SET_FOCUSED_WINDOW = 20, // supports ghi.guest.setFocusedWindow GHI_CAP_GET_EXEC_INFO_HASH = 21, // supports ghi.guest.getExecInfoHash + UNITY_CAP_STICKY_WINDOWS = 22, // supports unity.window.{un,}stick } GuestCapabilities; typedef struct { @@ -129,6 +130,7 @@ static GuestCapElem guestCapTable[] = { { GHI_CAP_TRAY_ICONS, GHI_CAP_VMDB_PATH, "trayIcons" }, { GHI_CAP_SET_FOCUSED_WINDOW, GHI_CAP_VMDB_PATH, "setFocusedWindow"}, { GHI_CAP_GET_EXEC_INFO_HASH, GHI_CAP_VMDB_PATH, "getExecInfoHash"}, + { UNITY_CAP_STICKY_WINDOWS, UNITY_CAP_VMDB_PATH, "sticky"}, }; #endif // VM_NEED_VMDB_GUEST_CAP_MAPPING diff --git a/open-vm-tools/lib/include/guestInfo.h b/open-vm-tools/lib/include/guestInfo.h index 669ad07d2..c76938fb5 100644 --- a/open-vm-tools/lib/include/guestInfo.h +++ b/open-vm-tools/lib/include/guestInfo.h @@ -110,11 +110,14 @@ typedef struct _DiskInfo { /* * Global functions + * + * XXX These belong in a bora-vmsoft header. */ #ifndef N_PLAT_NLM extern Bool GuestInfo_GetFqdn(int outBufLen, char fqdn[]); -extern Bool GuestInfo_GetNicInfo(GuestNicList *nicInfo); +extern Bool GuestInfo_GetNicInfo(NicInfoV3 **nicInfo); +extern void GuestInfo_FreeNicInfo(NicInfoV3 *nicInfo); extern Bool GuestInfo_GetDiskInfo(PGuestDiskInfo di); extern Bool GuestInfo_GetOSName(unsigned int outBufFullLen, unsigned int outBufLen, char *osNameFull, diff --git a/open-vm-tools/lib/include/hgfsHelper.h b/open-vm-tools/lib/include/hgfsHelper.h new file mode 100644 index 000000000..999a9384e --- /dev/null +++ b/open-vm-tools/lib/include/hgfsHelper.h @@ -0,0 +1,38 @@ +/********************************************************* + * Copyright (C) 2009 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. + * + *********************************************************/ + +/* + * hgfsClient.h + * + * Provides a helper library for guest applications to access + * the HGFS file system. + */ + +#ifndef _HGFS_HELPER_H_ +#define _HGFS_HELPER_H_ + +#include "vm_basic_types.h" +#include "unicode.h" + +Bool HgfsHlpr_QuerySharesDefaultRootPath(Unicode *hgfsRootPath); +void HgfsHlpr_FreeSharesRootPath(Unicode hgfsRootPath); +#if defined(_WIN32) +Bool HgfsHlpr_ReadRegistryDefaultRootPath(Unicode *hgfsRootPath); +#endif // _WIN32 + +#endif diff --git a/open-vm-tools/lib/include/hgfsProto.h b/open-vm-tools/lib/include/hgfsProto.h index 3651448e9..09e82030e 100644 --- a/open-vm-tools/lib/include/hgfsProto.h +++ b/open-vm-tools/lib/include/hgfsProto.h @@ -117,6 +117,34 @@ typedef enum { HGFS_OP_QUERY_VOLUME_INFO_V3, /* Query volume information */ HGFS_OP_CREATE_SYMLINK_V3, /* Create a symlink */ HGFS_OP_SERVER_LOCK_CHANGE_V3, /* Change the oplock on a file */ + HGFS_OP_WRITE_WIN32_STREAM_V3, /* Write WIN32_STREAM_ID format data to file */ + + /* + * Operations for version 4, deprecating version 3 operations. + */ + + HGFS_OP_CREATE_SESSION_V4, /* Create a session and return host capabilities. */ + HGFS_OP_DESTROY_SESSION_V4, /* Destroy/close session. */ + HGFS_OP_OPEN_V4, /* Open file */ + HGFS_OP_DIRECTORY_READ_V4, /* Read directory entries. */ + HGFS_OP_ENUMERATE_STREAMS_V4, /* Enumerate alternative named streams for a file. */ + HGFS_OP_GETATTR_V4, /* Get file attributes */ + HGFS_OP_SETATTR_V4, /* Set file attributes */ + HGFS_OP_DELETE_V4, /* Delete a file or a directory */ + HGFS_OP_LINKMOVE_V4, /* Rename/move/create hard link. */ + HGFS_OP_FSCTL_V4, /* Sending FS control requests. */ + HGFS_OP_ACCESS_CHECK_V4, /* Flush all cached data to the disk. */ + HGFS_OP_FSYNC_V4, /* Access check. */ + HGFS_OP_QUERY_VOLUME_INFO_V4, /* Query volume information. */ + HGFS_OP_OPLOCK_ACQUIRE_V4, /* Acquire OPLOCK. */ + HGFS_OP_OPLOCK_BREAK_V4, /* Break or downgrade OPLOCK. */ + HGFS_OP_LOCK_BYTE_RANGE_V4, /* Acquire byte range lock. */ + HGFS_OP_UNLOCK_BYTE_RANGE_V4, /* Release byte range lock. */ + HGFS_OP_QUERY_EAS_V4, /* Query extended attributes. */ + HGFS_OP_SET_EAS_V4, /* Add or modify extended attributes. */ + HGFS_OP_SET_WATCH_V4, /* Start monitoring directory changes. */ + HGFS_OP_REMOVE_WATCH_V4, /* Stop monitoring directory changes. */ + HGFS_OP_NOTIFY_V4, /* Notification for a directory change event. */ HGFS_OP_MAX, /* Dummy op, must be last in enum */ } HgfsOp; @@ -405,6 +433,13 @@ typedef uint64 HgfsAttrFlags; #define HGFS_ATTR_HIDDEN_FORCED (1 << 3) #define HGFS_ATTR_REPARSE_POINT (1 << 4) +/* V4 additional definitions for hgfsAttrFlags. */ +#define HGFS_ATTR_COMPRESSED (1 << 5) +#define HGFS_ATTR_ENCRYPTED (1 << 6) +#define HGFS_ATTR_OFFLINE (1 << 7) +#define HGFS_ATTR_READONLY (1 << 8) +#define HGFS_ATTR_SPARSE (1 << 9) +#define HGFS_ATTR_TEMPORARY (1 << 10) /* * Specifies which open request fields contain @@ -427,6 +462,10 @@ typedef uint64 HgfsOpenValid; #define HGFS_OPEN_VALID_SERVER_LOCK (1 << 10) #define HGFS_OPEN_VALID_FILE_NAME (1 << 11) +/* V4 additional open mask flags. */ +#define HGFS_OPEN_VALID_EA (1 << 12) +#define HGFS_OPEN_VALID_ACL (1 << 13) +#define HGFS_OPEN_VALID_STREAM_NAME (1 << 14) /* * Specifies which attribute fields contain @@ -883,6 +922,39 @@ struct HgfsReplyWriteV3 { #include "vmware_pack_end.h" HgfsReplyWriteV3; +/* Stream write flags */ +typedef enum { + HGFS_WIN32_STREAM_IGNORE_SECURITY = (1<<0), +} HgfsWin32StreamFlags; + +/* + * HgfsRequestWriteWin32Stream. + * Server must support HGFS_LARGE_PACKET_MAX to implement this op. + */ + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestWriteWin32StreamV3 { + HgfsHandle file; /* Opaque file ID used by the server */ + HgfsWin32StreamFlags flags; + uint32 reserved1; + uint32 requiredSize; + uint64 reserved2; /* Reserved for future use */ + char payload[1]; +} +#include "vmware_pack_end.h" +HgfsRequestWriteWin32StreamV3; + + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyWriteWin32StreamV3 { + uint32 actualSize; + uint64 reserved; /* Reserved for future use */ +} +#include "vmware_pack_end.h" +HgfsReplyWriteWin32StreamV3; + /* Deprecated */ @@ -1606,5 +1678,960 @@ struct HgfsReplySymlinkCreateV3 { #include "vmware_pack_end.h" HgfsReplySymlinkCreateV3; +/* HGFS protocol version 4 definitions. */ + +/* + * HGFS_PACKET_FLAG_NOTIFICATION set in flags field means that + * this is a notification or a callback request (not a reply to client request). + */ + +#define HGFS_PACKET_FLAG_NOTIFICATION (1 << 0) + +typedef +#include "vmware_pack_begin.h" +struct HgfsHeader { + uint8 version; /* Header version. */ + uint8 reserved1[3]; /* Reserved for future use. */ + uint8 dummy; /* Needed to distinguish between older and newer header. */ + uint8 reserved2[3]; /* Reserved for future use. */ + uint32 packetSize; /* Size of the packet, including the header size. */ + uint32 headerSize; /* Size of the Hgfs header. */ + uint32 requestId; /* Request ID. */ + uint32 op; /* Operation. */ + uint32 status; /* Return value. */ + uint32 flags; /* Flags. */ + uint32 information; /* Generic field, used e.g. for native error code. */ + uint64 sessionId; /* Session ID. */ + uint64 reserved; /* Reserved for future use. */ +} +#include "vmware_pack_end.h" +HgfsHeader; + +/* + * Flag HGFS_REQUEST_SUPPORTED is set for every requests that are supported by the host. + */ +#define HGFS_REQUEST_SUPPORTED (1 << 0) + +/* + * Following flags define which optional parameters for file open + * requests are supported by the host. + * HGFS_OPENV4_SUPPORTS_EA - host is capable of setting EA when creating + * a new file. + * HGFS_OPENV4_SUPPORTS_ACL - host is capable of setting ACLs when creating + * a new file. + * HGFS_OPENV4_SUPPORTS_NAMED_STREAMS - opening/enumerating named streams + * is supported. + * HGFS_OPENV4_SUPPORTS_SHARED_ACCESS - host supports file sharing restrictions. + * HGFS_OPENV4_SUPPORTS_UNIX_PERMISSIONS - host stores POSIX permissions with + * file. + * HGFS_OPENV4_POSIX_FILE_DELETION - host supports POSIX file deletion semantics. + */ +typedef uint32 HgfsOpenV4Capabilities; +#define HGFS_OPENV4_SUPPORTS_EA (1 << 1) +#define HGFS_OPENV4_SUPPORTS_ACL (1 << 2) +#define HGFS_OPENV4_SUPPORTS_NAMED_STREAMS (1 << 3) +#define HGFS_OPENV4_SUPPORTS_SHARED_ACCESS (1 << 4) +#define HGFS_OPENV4_SUPPORTS_UNIX_PERMISSIONS (1 << 5) +#define HGFS_OPENV4_POSIX_FILE_DELETION (1 << 6) + +/* + * There is a significant difference in byte range locking semantics between Windows + * and POSIX file systems. Windows implements mandatory locking which means that every + * read or write request that conflicts with byte range locks is rejected. POSIX has + * an advisory locking which means that locks are validated only when another lock is + * requested and are not enforced for read/write operations. + * Applications in guest OS may expect byte range locking semantics that matches guest + * OS which may be different from semantics that is natively supported by host OS. In + * this case either HGFS server or HGFS client should provide compensation for the host + * OS semantics to maintain application compatibility. + * Client must know if the server is capable to provide appropriate byte range locking + * semantics to perform some compensation on behalf of server when necessary. + * + * Following flags define various capabilities of byte range lock implementation on + * the host. + * + * HGFS_BYTE_RANGE_LOCKS_SUPPORTS_64 means that server is capable of locking 64 bit + * length ranges. + * HGFS_BYTE_RANGE_LOCKS_SUPPORTS_32 means that server is limited to 32-bit ranges. + * HGFS_BYTE_RANGE_LOCKS_SUPPORTS_MANDATORY means that server is capable of enforcing + * read/write restrictions for locked ranges. + * HGFS_BYTE_RANGE_LOCKS_SUPPORTS_ADVISORY means that server supports advisory locking; + * locks are validated only for other bytes + * range locking and are not enforced + * for read/write operations. + */ +typedef uint32 HgfsByteRangeLockingCapabilities; +#define HGFS_BYTE_RANGE_LOCKS_SUPPORTS_64 (1 << 1) +#define HGFS_BYTE_RANGE_LOCKS_SUPPORTS_32 (1 << 2) +#define HGFS_BYTE_RANGE_LOCKS_SUPPORTS_MANDATORY (1 << 3) +#define HGFS_BYTE_RANGE_LOCKS_SUPPORTS_ADVISORY (1 << 4) + +/* HGFS_SUPPORTS_HARD_LINKS is set when the host supports hard links. */ +typedef uint32 HgfsLinkMoveCapabilities; +#define HGFS_SUPPORTS_HARD_LINKS (1 << 1) + + /* + * HGFS_SET_WATCH_SUPPORTS_FINE_GRAIN_EVENTS is set when host supports + * fine grain event reporting for directory notification. + */ +typedef uint32 HgfsSetWatchCapabilities; +#define HGFS_SET_WATCH_SUPPORTS_FINE_GRAIN_EVENTS (1 << 1) + + +typedef +#include "vmware_pack_begin.h" +struct HgfsCapability { + HgfsOp op; /* Op. */ + uint32 flags; /* Flags. */ +} +#include "vmware_pack_end.h" +HgfsCapability; + +typedef HgfsFileName HgfsUserName; +typedef HgfsFileName HgfsGroupName; + +/* Following structures describe user identity on the host which runs HGFS service. */ + +typedef +#include "vmware_pack_begin.h" +struct HgfsIdentity { + uint32 uid; /* user id. */ + uint32 gid; /* Primary group id. */ + HgfsUserName user; /* User name in form specified in RFC 3530. */ + HgfsGroupName group; /* Group name in form specified in RFC 3530. */ +} +#include "vmware_pack_end.h" +HgfsIdentity; + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestCreateSession { + uint32 numCapabilities; /* Number of capabilities to follow. */ + uint32 maxPacketSize; /* Maximum packet size supported. */ + uint64 reserved; /* Reserved for future use. */ + HgfsCapability capabilities[1]; /* Array of HgfsCapabilities. */ +} +#include "vmware_pack_end.h" +HgfsRequestCreateSession; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyCreateSession { + uint64 sessionId; /* Session ID. */ + uint32 numCapabilities; /* Number of capabilities to follow. */ + uint32 maxPacketSize; /* Maximum packet size supported. */ + uint32 identityOffset; /* Offset to HgfsIdentity or 0 if no identity. */ + uint64 reserved; /* Reserved for future use. */ + HgfsCapability capabilities[1]; /* Array of HgfsCapabilities. */ +} +#include "vmware_pack_end.h" +HgfsReplyCreateSession; + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestDestroySession { + uint64 sessionId; /* Session ID. */ + uint64 reserved; /* Reserved for future use. */ +} +#include "vmware_pack_end.h" +HgfsRequestDestroySession; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyDestroySession { + uint64 reserved; /* Reserved for future use. */ +} +#include "vmware_pack_end.h" +HgfsReplyDestroySession; + +/* Adds new error status: HGFS_STATUS_INVALID_SESSION. */ + +/* + * If file handle is used to set watch (HGFS_FILE_NAME_USE_FILE_DESC + * is set in the fileName), closing this handle implicitly removes the watch. + */ +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestSetWatch { + uint64 events; /* What events to watch? */ + uint32 flags; /* Flags. */ + uint64 reserved; /* Reserved for future use. */ + HgfsFileNameV3 fileName; /* Filename to watch. */ +} +#include "vmware_pack_end.h" +HgfsRequestSetWatch; + +/* + * Coarse grain notification event types. + */ +#define HGFS_ACTION_ADDED (1 << 0) /* File was added. */ +#define HGFS_ACTION_REMOVED (1 << 1) /* File was removed. */ +#define HGFS_ACTION_MODIFIED (1 << 2) /* File attributes were changed. */ +#define HGFS_ACTION_RENAMED (1 << 3) /* File was renamed. */ + +/* + * Fine grain notification event types. + * HgfsRequestSetWatch events. + * Events marked with (*) apply only to directories. + */ +#define HGFS_NOTIFY_ACCESS (1 << 0) /* File accessed (read) */ +#define HGFS_NOTIFY_ATTRIB (1 << 1) /* Windows file attributes changed. */ +#define HGFS_NOTIFY_SIZE (1 << 2) /* File size changed. */ +#define HGFS_NOTIFY_ATIME (1 << 3) /* Access time changed. */ +#define HGFS_NOTIFY_MTIME (1 << 4) /* Modification time changed. */ +#define HGFS_NOTIFY_CTIME (1 << 5) /* Attribute change time changed. */ +#define HGFS_NOTIFY_CRTIME (1 << 6) /* Creation time changed. */ +#define HGFS_NOTIFY_NAME (1 << 7) /* File / Directory name changed. */ +#define HGFS_NOTIFY_OPEN (1 << 8) /* File opened */ +#define HGFS_NOTIFY_CLOSE_WRITE (1 << 9) /* File opened for writing closed */ +#define HGFS_NOTIFY_CLOSE_NOWRITE (1 << 10) /* File opened for reading closed */ +#define HGFS_NOTIFY_CREATE (1 << 11) /* File / directory created */ +#define HGFS_NOTIFY_DELETE (1 << 12) /* (*) File / directory deleted */ +#define HGFS_NOTIFY_DELETE_SELF (1 << 13) /* Watched file / directory deleted */ +#define HGFS_NOTIFY_MODIFY (1 << 14) /* File or directory modified. */ +#define HGFS_NOTIFY_MOVE_SELF (1 << 15) /* Watched file / directory moved. */ +#define HGFS_NOTIFY_MOVE_FROM (1 << 16) /* (*) Moved out of watched directory. */ +#define HGFS_NOTIFY_MOVE_TO (1 << 17) /* (*) Moved into watched directory. */ +#define HGFS_NOTIFY_RENAME (1 << 18) /* File / directory name changed. */ + +/* HgfsRequestSetWatch flags. */ +#define HGFS_NOTIFY_FLAG_WATCH_TREE (1 << 0) /* Watch the entire directory tree. */ +#define HGFS_NOTIFY_FLAG_DONT_FOLLOW (1 << 1) /* Don't follow symlinks. */ +#define HGFS_NOTIFY_FLAG_ONE_SHOT (1 << 2) /* Generate only one notification. */ +#define HGFS_NOTIFY_FLAG_POSIX_HINT (1 << 3) /* Client is POSIX and thus expects + * fine grain notification. Server + * may provide coarse grain + * notification even if this flag is + * set. + */ + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplySetWatch { + HgfsHandle watchId; /* Watch identifier for subsequent references. */ + uint64 reserved; /* Reserved for future use. */ +} +#include "vmware_pack_end.h" +HgfsReplySetWatch; + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestRemoveWatch { + HgfsHandle watchId; /* Watch identifier to remove. */ +} +#include "vmware_pack_end.h" +HgfsRequestRemoveWatch; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyRemoveWatch { + uint64 reserved; /* Reserved for future use. */ +} +#include "vmware_pack_end.h" +HgfsReplyRemoveWatch; + +typedef +#include "vmware_pack_begin.h" +struct HgfsNotifyEvent { + uint32 nextOffset; /* Offset of next event; 0 if it i sthe last one. */ + uint64 mask; /* Event occurred. */ + uint64 reserved; /* Reserved for future use. */ + HgfsFileName fileName; /* Filename. */ + HgfsFileName oldName; /* New filename for rename operation. */ +} +#include "vmware_pack_end.h" +HgfsNotifyEvent; + +/* Too many events, some or all event were dropped by the server. */ +#define HGFS_NOTIFY_FLAG_OVERFLOW (1 << 0) +/* Watch had been removed either explicitly or implicitly. */ +#define HGFS_NOTIFY_FLAG_REMOVED (1 << 1) +/* Server generated coasrse grain events. */ +#define HGFS_NOTIFY_FLAG_COARSE_GRAIN (1 << 2) + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestNotify { + HgfsHandle watchId; /* Watch identifier. */ + uint32 flags; /* Various flags. */ + uint32 count; /* Number of events occured. */ + uint64 reserved; /* Reserved for future use. */ + HgfsNotifyEvent events[1]; /* Events. HgfsNotifyEvent(s). */ +} +#include "vmware_pack_end.h" +HgfsRequestNotify; + +// Query EA flags values. +#define HGFS_QUERY_EA_INDEX_SPECIFIED (1 << 0) +#define HGFS_QUERY_EA_SINGLE_ENTRY (1 << 1) +#define HGFS_QUERY_EA_RESTART_SCAN (1 << 2) + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestQueryEA { + uint32 flags; /* EA flags. */ + uint32 index; + uint64 reserved; /* Reserved for future use. */ + uint32 eaNameLength; /* EA name length. */ + uint32 eaNameOffset; /* Offset of the eaName field. */ + HgfsFileNameV3 fileName; /* File to watch. */ + char eaNames[1]; /* List of NULL terminated EA names. + * Actual location of the data depends on + * fileName length and defined by eaNameOffset. + */ +} +#include "vmware_pack_end.h" +HgfsRequestQueryEA; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyQueryEA { + uint32 nextOffset; /* Offset of the next structure when more then + * one record is returned. + */ + uint32 flags; /* EA flags. */ + uint32 index; /* Index needed to resume scan. */ + uint64 reserved; /* Reserved for future use. */ + uint32 eaDataLength; /* EA value length. */ + char eaData[1]; /* NULL termianed EA name followed by EA value. */ +} +#include "vmware_pack_end.h" +HgfsReplyQueryEA; + + +typedef +#include "vmware_pack_begin.h" +struct HgfsEA { + uint32 nextOffset; /* Offset of the next structure in the chain. */ + uint32 valueLength; /* EA value length. */ + char data[1]; /* NULL terminated EA name followed by EA value. */ +} +#include "vmware_pack_end.h" +HgfsEA; + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestSetEA { + uint32 flags; /* Flags, see below. */ + uint64 reserved; /* Reserved for future use. */ + uint32 numEAs; /* Number of EAs in this request. */ + HgfsEA attributes[1]; /* Array of attributes. */ +} +#include "vmware_pack_end.h" +HgfsRequestSetEA; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplySetEA { + uint64 reserved; /* Reserved for future use. */ +} +#include "vmware_pack_end.h" +HgfsReplySetEA; + +/* + * EA Flags. When both flags are set EA is either created or replaced if it exists. + * HGFS_EA_FLAG_CREATE - create if EA is not present, error otherwise. + * HGFS_EA_FLAG_REPLACE - Replace exisitng EA. Error if EA not already present. + */ +#define HGFS_EA_FLAG_CREATE (1 << 0) +#define HGFS_EA_FLAG_REPLACE (1 << 1) + +/* + * Byte range lock flag values: + * HGFS_RANGE_LOCK_EXCLUSIVE - Requested lock is exclusive when this flag is set, + * otherwise it is a shared lock. + * HGFS_RANGE_LOCK_FAIL_IMMEDIATLY - If the flag is not set server waits until the + * lock becomes available. + */ +#define HGFS_RANGE_LOCK_EXCLUSIVE (1 << 0) +#define HGFS_RANGE_LOCK_FAIL_IMMEDIATLY (1 << 1) + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestLockRange { + HgfsHandle fid; /* File to take lock on. */ + uint32 flags; /* Various flags. */ + uint64 start; /* Starting offset in the file. */ + uint64 length; /* Number of bytes to lock. */ + uint64 reserved; /* Reserved for future use. */ +} +#include "vmware_pack_end.h" +HgfsRequestLockRange; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyLockRange { + uint64 reserved; /* Reserved for future use. */ +} +#include "vmware_pack_end.h" +HgfsReplyLockRange; + +#define HGFS_RANGE_LOCK_UNLOCK_ALL (1 << 0) + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestUnlockRange { + HgfsHandle fid; /* File to take lock on. */ + uint32 flags; /* Various flags. */ + uint64 start; /* Starting offset in the file. */ + uint64 length; /* Number of bytes to lock. */ +} +#include "vmware_pack_end.h" +HgfsRequestUnlockRange; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyUnlockRange { + uint64 reserved; /* Reserved for future use. */ +} +#include "vmware_pack_end.h" +HgfsReplyUnlockRange; + +/* + * There are three types of oplocks: level 1, batch, and level 2. Both the level 1 and + * batch oplocks are "exclusive access" opens. They are used slightly differently, + * however, and hence have somewhat different semantics. A level 2 oplock is a "shared + * access" grant on the file. + * Level 1 is used by a remote client that wishes to modify the data. Once granted a + * Level 1 oplock, the remote client may cache the data, modify the data in its cache + * and need not write it back to the server immediately. + * Batch oplocks are used by remote clients for accessing script files where the file is + * opened, read or written, and then closed repeatedly. Thus, a batch oplock + * corresponds not to a particular application opening the file, but rather to a remote + * clients network file system caching the file because it knows something about the + * semantics of the given file access. The name "batch" comes from the fact that this + * behavior was observed by Microsoft with "batch files" being processed by command line + * utilities. Log files especially exhibit this behavior when a script it being + * processed each command is executed in turn. If the output of the script is redirected + * to a log file the file fits the pattern described earlier, namely open/write/close. + * With many lines in a file this pattern can be repeated hundreds of times. + * Level 2 is used by a remote client that merely wishes to read the data. Once granted + * a Level 2 oplock, the remote client may cache the data and need not worry that the + * data on the remote file server will change without it being advised of that change. + * An oplock must be broken whenever the cache consistency guarantee provided by the + * oplock can no longer be provided. Thus, whenever a second network client attempts to + * access data in the same file across the network, the file server is responsible for + * "breaking" the oplocks and only then allowing the remote client to access the file. + * This ensures that the data is guaranteed to be consistent and hence we have preserved + * the consistency guarantees essential to proper operation. + * + * HGFS_OPLOCK_NONE: no oplock. No caching on client side. + * HGFS_OPLOCK_SHARED: shared (or LEVEL II) oplock. Read caching is allowed. + * HGFS_OPLOCK_EXCLUSIVE: exclusive (or LEVEL I) oplock. Read/write caching is allowed. + * HGFS_OPLOCK_BATCH: batch oplock. Read/Write and Open caching is allowed. + */ + +typedef enum { + HGFS_OPLOCK_NONE, + HGFS_OPLOCK_SHARED, + HGFS_OPLOCK_EXCLUSIVE, + HGFS_OPLOCK_BATCH, +} HgfsOpportunisticLock; + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestServerLockChangeV2 { + HgfsHandle fid; /* File to take lock on. */ + HgfsOpportunisticLock serverLock; /* Lock type. */ + uint64 reserved; +} +#include "vmware_pack_end.h" +HgfsRequestServerLockChangeV2; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyServerLockChangeV2 { + HgfsOpportunisticLock serverLock; /* Lock granted. */ + uint64 reserved; +} +#include "vmware_pack_end.h" +HgfsReplyServerLockChangeV2; + +/* + * This request is sent from server to the client to notify that oplock + * is revoked or downgraded. + */ + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestOplockBreakV4 { + HgfsHandle fid; /* File handle. */ + HgfsOpportunisticLock serverLock; /* Lock downgraded to this type. */ + uint64 reserved; /* Reserved for future use. */ +} +#include "vmware_pack_end.h" +HgfsRequestOplockBreakV4; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyOplockBreakV4 { + uint64 reserved; /* Reserved for future use. */ +} +#include "vmware_pack_end.h" +HgfsReplyOplockBreakV4; + +/* + * Flusing of a whole volume is not supported. + * Flusing of reqular files is supported on all hosts. + * Flusing of directories is supproted on POSIX hosts and is + * NOOP on Windows hosts. + */ +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestFsyncV4 { + HgfsHandle fid; /* File to sync. */ + uint64 reserved; +} +#include "vmware_pack_end.h" +HgfsRequestFsyncV4; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyFsyncV4 { + uint64 reserved; +} +#include "vmware_pack_end.h" +HgfsReplyFsyncV4; + +/* + * This request is name based only. + * Server fails this request if HGFS_FILE_E_USE_FILE_DESC is set in the fileName. + */ +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestAccessCheckV4 { + HgfsFileNameV3 fileName; /* File concerned. */ + HgfsPermissions perms; /* Permissions to check for. */ + uint64 reserved; /* Reserved for future use. */ +} +#include "vmware_pack_end.h" +HgfsRequestAccessCheckV4; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyAccessCheckV4 { + uint64 reserved; /* Reserved for future use. */ +} +#include "vmware_pack_end.h" +HgfsReplyAccessCheckV4; + +/* + * Additional HgfsPersmissions type: checks file existense without + * requesting any particular access. + * Matches F_OK mode parameter for POSIX access (2) API. + */ +#define HGFS_PERM_EXISTS 8 + +/* + * HGFS_PLATFORM_ALL is a HGFS specific platform independent FSCTL + * that correspond to different OS specific codes. + * Other types of FSCTL are platform specific to allow better user + * experience when guest and host OS are the same. HGFS does not interpret + * platform specific FSCTL in any way, it just passes it through to the + * host. If the host run appropriate OS it executes FSCTL on user's behalf, + * otherwise it fails the request. + */ +typedef enum HgfsPlatformType { + HGFS_PLATFORM_ALL, + HGFS_PLATFORM_WINDOWS, + HGFS_PLATFORM_LINUX, + HGFS_PLATFORM_MAC +}HgfsPlatformType; + +#define HGFS_FSCTL_SET_SPARSE 1 /* Platform independent FSCTL to make file sparse. */ + +/* Platform together with the code define exact meaning of the operation. */ +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestFsctlV4 { + HgfsHandle fid; + uint32 code; + HgfsPlatformType platform; + uint32 dataLength; + char data[1]; +} +#include "vmware_pack_end.h" +HgfsRequestFsctlV4; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyFsctlV4 { + uint32 dataLength; + char data[1]; +} +#include "vmware_pack_end.h" +HgfsReplyFsctlV4; + +/* + * Creating a new file or reading file attributes involves ACL. There is a good + * definition of multi-platform ACLs in RFC 3530, section 5.11. HGFS should use + * ACLs defined in this document (http://tools.ietf.org/html/rfc3530#section-5.11). + * ACL support is not mandatory. If a request to create file with ACL comes to a host + * that does not support ACL, the request should succeed and setting ACL is ignored. + * Such behavior is consistent with other file systems. + */ +typedef uint64 HgfsOpenCreateOptions; + +/* O_SYMLINK in Mac OS or FILE_FLAG_OPEN_REPARSE_POINT in Windows. */ +#define HGFS_OPENCREATE_OPTION_SYMLINK (1 << 0) +/* O_SHLOCK in Mac OS or obtain shared range lock for the whole file. */ +#define HGFS_OPENCREATE_OPTION_SHLOCK (1 << 1) +/* O_EXLOCK in Mac OS or obtain exclusive range lock for the whole file. */ +#define HGFS_OPENCREATE_OPTION_EXLOCK (1 << 2) +/* O_SYNC in Linux, ignored in Mac, FILE_FLAG_WRITE_THROUGH in Windows. */ +#define HGFS_OPENCREATE_OPTION_WRITETHROUGH (1 << 3) +/* FILE_FLAG_NO_BUFFERING in Windows, O_SYNC in Linux, ignored on Mac OS. */ +#define HGFS_OPENCREATE_OPTION_NO_BUFERING (1 << 4) +/* + * O_NOFOLLOW in POSIX. Windows server checks for reparse point + * and fails the request if file has one. + */ +#define HGFS_OPENCREATE_OPTION_NO_FOLLOW (1 << 5) +/* FILE_FLAG_NO_RECALL in Windows. Ignored by POSIX host. */ +#define HGFS_OPENCREATE_OPTION_NO_RECALL (1 << 6) +/* FILE_FLAG_RANDOM_ACCESS in Windows. Ignored by POSIX host. */ +#define HGFS_OPENCREATE_OPTION_RANDOM (1 << 7) +/* FILE_FLAG_SEQUENTIAL_SCAN in Windows. Ignored by POSIX host. */ +#define HGFS_OPENCREATE_OPTION_SEQUENTIAL (1 << 8) +/* FILE_FLAG_BACKUP_SEMANTICS in Windows. Ignored by POSIX host. */ +#define HGFS_OPENCREATE_OPTION_BACKUP_SEMANTICS (1 << 9) +/* Fail opening if the file already exists and it is not a directory. */ +#define HGFS_OPENCREATE_OPTION_DIRECTORY (1 << 10) +/* Fail opening if the file already exists and it is a directory. */ +#define HGFS_OPENCREATE_OPTION_NON_DIRECTORY (1 << 11) + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestOpenV4 { + HgfsOpenValid mask; /* Bitmask that specified which fields are valid. */ + HgfsOpenMode mode; /* Which type of access requested. See desiredAccess */ + HgfsOpenFlags flags; /* Which flags to open the file with */ + HgfsPermissions specialPerms; /* Desired 'special' permissions for file creation */ + HgfsPermissions ownerPerms; /* Desired 'owner' permissions for file creation */ + HgfsPermissions groupPerms; /* Desired 'group' permissions for file creation */ + HgfsPermissions otherPerms; /* Desired 'other' permissions for file creation */ + HgfsAttrFlags attr; /* Attributes, if any, for file creation */ + uint64 allocationSize; /* How much space to pre-allocate during creation */ + uint32 desiredAccess; /* Extended support for windows access modes */ + uint32 shareAccess; /* Windows only, share access modes */ + HgfsOpenCreateOptions createOptions; /* Various options. */ + HgfsOpportunisticLock requestedLock; /* The type of lock desired by the client */ + HgfsFileNameV3 fileName; /* fid can be used only for relative open, + * i.e. to open named stream. + */ + HgfsFileName streamName; /* Name of the alternative named stream. + * All flags are the same as defined in fileName. + * The name is used in conjuction with fileName + * field, for example if Windows opens file + * "abc.txt:stream" then fileName contains + * "abc.txt" and streamName contains "stream" + */ + /* + * EA to set if the file is created or overwritten. The parameter should be ignored + * if the file already exists. + * It is needed to correctly implement Windows semantics for opening files. + * It should work atomically - failure to add EA should result in failure to create + * the new file. + * If the host file system does not support EA server should fail the request rather + * then succeeding and silently dropping EA. + */ + HgfsRequestSetEA extendedAttributes; + uint32 aclLength; /* Length of the acl field. */ + char acl[1]; /* Multi-platform ACL as defined in RFC 3530. */ +} +#include "vmware_pack_end.h" +HgfsRequestOpenV4; + +typedef enum HgfsOpenResult { + HGFS_FILE_OPENED, + HGFS_FILE_CREATED, + HGFS_FILE_OVERWRITTEN, + HGFS_FILE_SUPERSIDED, + } HgfsOpenResult; + +/* + * Win32 API has a special value for the desired access - MAXIMUM_ALLOWED. + * Such desired access means that file system must grant as much rights for the file + * as it is allowed for the current user. + * HGFS client must know what access rights were granted to properly communicate this + * information to the IoManager; grantedAccess field is used for this purpose. + */ +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyOpenV4 { + HgfsHandle file; /* Opaque file ID used by the server */ + HgfsOpportunisticLock grantedLock; /* The type of lock acquired by the server */ + HgfsOpenResult openResult; /* Opened/overwritten or a new file created? */ + uint32 grantedAccess; /* Granted access rights. */ + uint64 fileId; /* Persistent volume-wide unique file id. */ + uint64 volumeId; /* Persistent unique volume id. */ +} +#include "vmware_pack_end.h" +HgfsReplyOpenV4; + +/* + * Flags that define behaviour of the move/creating hard link operation. + */ +typedef uint64 HgfsMoveLinkFlags; + +#define HGFS_LINKMOVE_FLAG_REPLACE_EXISTING (1 << 0) /* Delete existing target. */ +#define HGFS_LINKMOVE_FLAG_HARD_LINK (1 << 1) /* Create hard link. */ + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestLinkMoveV4 { + HgfsFileNameV3 oldFileName; /* Path to the exisitng source file.*/ + HgfsFileNameV3 newFileName; /* Path to the destinatio name.*/ + HgfsMoveLinkFlags flags; /* Flags that define behaviour of the operation.*/ +} +#include "vmware_pack_end.h" +HgfsRequestLinkMoveV4; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyLinkMove4 { + uint64 reserved; /* Reserved for future use. */ +} +#include "vmware_pack_end.h" +HgfsReplyLinkMove4; + +/* + * HgfsQueryVolumeMaskV4 mask in a request defines which volume properties client needs; + * mask in a reply defines which properties were actually returned by the host. + * + * HGFS_QUERY_VOLUME_MASK_SIZE controls totalBytes, freeBytes and availableBytes. + * HGFS_QUERY_VOLUME_MASK_FS_CAPABILITIES controls capabilities. + * HGFS_QUERY_VOLUME_MASK_ATTRIBUTES controls creationTime. + * HGFS_QUERY_VOLUME_MASK_VOLUME_GEOMETRY controls bytesPerSector and sectorPerCluster. + * HGFS_QUERY_VOLUME_MASK_VOLUME_LABEL controls volume label. + * HGFS_QUERY_VOLUME_MASK_FS_NAME controls fileSystemName. + */ +typedef uint64 HgfsQueryVolumeMaskV4; + +#define HGFS_QUERY_VOLUME_MASK_SIZE (1 << 0) +#define HGFS_QUERY_VOLUME_MASK_ATTRIBUTES (1 << 1) +#define HGFS_QUERY_VOLUME_MASK_FS_CAPABILITIES (1 << 2) +#define HGFS_QUERY_VOLUME_MASK_VOLUME_LABEL (1 << 3) +#define HGFS_QUERY_VOLUME_MASK_VOLUME_GEOMETRY (1 << 4) +#define HGFS_QUERY_VOLUME_MASK_FS_NAME (1 << 5) + +typedef uint64 HgfsFileSystemCapabilities; +#define HGFS_VOLUME_CASE_SENSITIVE (1 << 0) +#define HGFS_VOLUME_SUPPORTS_EA (1 << 1) +#define HGFS_VOLUME_SUPPORTS_COMPRESSION (1 << 2) +#define HGFS_VOLUME_SUPPORTS_SHORT_NAMES (1 << 3) +#define HGFS_VOLUME_SUPPORTS_ACL (1 << 4) +#define HGFS_VOLUME_READ_ONLY (1 << 5) +#define HGFS_VOLUME_SUPPORTS_ENCRYPTION (1 << 6) +#define HGFS_VOLUME_SUPPORTS_OBJECT_ID (1 << 7) +#define HGFS_VOLUME_SUPPORTS_REMOTE_STORAGE (1 << 8) +#define HGFS_VOLUME_SUPPORTS_SYMLINKS (1 << 9) +#define HGFS_VOLUME_SUPPORTS_SPARSE_FILES (1 << 10) +#define HGFS_VOLUME_SUPPORTS_UNICODE (1 << 11) +#define HGFS_VOLUME_SUPPORTS_QUOTA (1 << 12) +#define HGFS_VOLUME_SUPPORTS_NAMED_STREAMS (1 << 13) + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestQueryVolumeV4 { + HgfsQueryVolumeMaskV4 mask; + HgfsFileNameV3 name; +} +#include "vmware_pack_end.h" +HgfsRequestQueryVolumeV4; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyQueryVolumeV4 { + HgfsQueryVolumeMaskV4 mask; /* Identifies which values were set by the host. */ + uint64 totalBytes; /* Total volume capacity. */ + uint64 freeBytes; /* Free space on the volume. */ + uint64 availableBytes; /* Free space available for the user. */ + HgfsFileSystemCapabilities capabilities; /* File system capabilities. */ + uint64 creationTime; /* Volume creation time. */ + uint32 bytesPerSector; /* Sector size for the volume. */ + uint32 sectorsPerCluster; /* Cluster size for the volume. */ + HgfsFileName volumeLabel; /* Volume name or label. */ + HgfsFileName fileSystemName;/* File system name. */ +} +#include "vmware_pack_end.h" +HgfsReplyQueryVolumeV4; + +typedef uint32 HgfsDirectoryReadMaskV4; +#define HGFS_DIRECTORY_READ_NAME (1 << 0) +#define HGFS_DIRECTORY_READ_SHORT_NAME (1 << 1) +#define HGFS_DIRECTORY_READ_FILE_SIZE (1 << 2) +#define HGFS_DIRECTORY_READ_ALLOCATION_SIZE (1 << 3) +#define HGFS_DIRECTORY_READ_EA_SIZE (1 << 4) +#define HGFS_DIRECTORY_READ_TIME_STAMP (1 << 5) +#define HGFS_DIRECTORY_READ_FILE_ATTRIBUTES (1 << 6) +#define HGFS_DIRECTORY_READ_FILE_NODE_TYPE (1 << 7) + +typedef uint32 HgfsDirectoryReadFlagsV4; +#define HGFS_DIRECTORY_READ_INITIAL_QUERY (1 << 1) +#define HGFS_DIRECTORY_READ_SINGLE_ENTRY (1 << 2) + +/* + * Read directory request can be used to enumerate files in a directory. + * File handle used in the request must be returned by HgfsRequestOpenV4 or later. + * searchPattern parameter allows filter out file names in the server for optimization. + * It is optional - host may ignore patterns and return entries that do not match + * the pattern. It is client responsibility to filter out names that do not match + * the pattern. + * + * The mask field in request allows client to specify which properties it is + * interested in. It allows to implement optimization in the server by skipping + * parameters which client does not need. + * + * Service fills mask field in the reply buffer to specify which of the requested + * properties it supports, which may be a subset of requested properties. + */ + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestReadDirectoryV4 { + HgfsDirectoryReadMaskV4 mask; + HgfsDirectoryReadFlagsV4 flags; + HgfsHandle fid; + uint32 restartIndex; + HgfsFileName searchPattern; +} +#include "vmware_pack_end.h" +HgfsRequestReadDirectoryV4; + +typedef +#include "vmware_pack_begin.h" +struct HgfsDirectoryEntryV4 { + uint32 nextEntryOffset; + uint32 fileIndex; + HgfsAttrFlags attributes; + HgfsFileType fileType; + uint64 fileSize; + uint64 allocationSize; + uint64 creationTime; + uint64 accessTime; + uint64 modificationTime; + uint64 changeAttributesTime; + uint32 eaSize; + HgfsFileName shortName; + HgfsFileName fileName; +} +#include "vmware_pack_end.h" +HgfsDirectoryEntryV4; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyReadDirectoryV4 { + uint32 numberEntriesReturned; + uint32 offsetToContinue; + HgfsDirectoryReadMaskV4 mask; /* Returned mask that may be a subset of requested mask. */ + HgfsDirectoryEntryV4 entries[1]; +} +#include "vmware_pack_end.h" +HgfsReplyReadDirectoryV4; + +/* + * File handle returned by HgfsRequestOpenV4 or later. Descriptors returned by + * HgfsHandle fid; earlier versions of HgfsRequestOpen are not supported. + */ +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestEnumerateStreamsV4 { + uint32 restartIndex; +} +#include "vmware_pack_end.h" +HgfsRequestEnumerateStreamsV4; + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestStreamEntryV4 { + uint32 nextEntryOffset; + uint32 fileIndex; + HgfsFileName fileName; +} +#include "vmware_pack_end.h" +HgfsRequestStreamEntryV4; + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestGetAttrV4 { + uint32 mask; + uint32 flags; + HgfsFileNameV3 name; +} +#include "vmware_pack_end.h" +HgfsRequestGetAttrV4; + +/* + * V4 reports different file size for symlinks then V3 or V2. + * It does not return file name length as EOF - it reports actual EOF. + * On POSIX the value is always 0 and on Windows it is an actual EOF of + * a file with a reparse point. + * Each client must adjust the value for file size according to guest OS rules. + * + * Mask in HgfsAttr2V2 should be extended to include short name, symlink target and ACL. + * If the host does not support a requested feature it is free to clear the + * correspondent bit in the mask and ignore the feature. + * + * Multi-platform notice: symbolic link is represented by a file with REPARSE_POINT + * on Windows. Thus Windows supports swtiching a file type between + * regular or directory => symlink and back. + * Setting symlinkTarget attribute on Windows host results in assigning + * reparse point to the host file. + */ + +typedef +#include "vmware_pack_begin.h" +struct HgfsAttrV4 { + HgfsAttrV2 attr; + uint32 numberOfLinks; + HgfsFileName shortName; + HgfsFileName symlinkTarget; + uint32 aclLength; + char acl[1]; +} +#include "vmware_pack_end.h" +HgfsAttrV4; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyGetAttrV4 { + HgfsAttrV4 attr; +} +#include "vmware_pack_end.h" +HgfsReplyGetAttrV4; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplySetAttrV4 { + uint32 mask; /* Defines which attributes were set. */ +} +#include "vmware_pack_end.h" +HgfsReplySetAttrV4; + +/* + * Unlike V3 deletion this command can be used to delete both files and directories. + * Its semantics depends on whether fid or file path is specified in the fileName. + * When path is used it implements/emulates POSIX semantics - name is deleted from + * the directory however if the file is opened it is still accessible. When fid is used + * the file name disappears from the folder only when the last handle for the file is + * closed - Windows style deletion. + */ + +typedef +#include "vmware_pack_begin.h" +struct HgfsRequestDeleteFileV4 { + HgfsFileNameV3 fileName; +} +#include "vmware_pack_end.h" +HgfsRequestDeleteFileV4; + +typedef +#include "vmware_pack_begin.h" +struct HgfsReplyDeleteFileV4 { + uint64 reserved; +} +#include "vmware_pack_end.h" +HgfsReplyDeleteFileV4; #endif /* _HGFS_PROTO_H_ */ diff --git a/open-vm-tools/lib/include/hgfsServerPolicy.h b/open-vm-tools/lib/include/hgfsServerPolicy.h index 09858f073..4339a795c 100644 --- a/open-vm-tools/lib/include/hgfsServerPolicy.h +++ b/open-vm-tools/lib/include/hgfsServerPolicy.h @@ -92,6 +92,12 @@ HgfsServerPolicy_GetShareOptions(char const *nameIn, // IN: Share name Bool HgfsServerPolicy_IsShareOptionSet(HgfsShareOptions shareOptions, // IN: Config options uint32 option); // IN: Option to check +HgfsNameStatus +HgfsServerPolicy_ProcessCPName(char const *nameIn, // IN: name in CPName form + size_t nameInLen, // IN: length of the name + Bool *readAccess, // OUT: Read permissions + Bool *writeAccess, // OUT: Write permissions + char const **shareBaseDir); // OUT: Shared directory void HgfsServerPolicy_FreeShareList(HgfsServerPolicy_ShareList *shareList); // IN: list to free @@ -99,4 +105,9 @@ HgfsServerPolicy_FreeShareList(HgfsServerPolicy_ShareList *shareList); // IN: li HgfsServerPolicy_ShareList * HgfsServerPolicy_GetSharesWithTag(const char *tag); // IN: tag to search for +Bool +HgfsServerPolicy_CheckMode(HgfsOpenMode mode, // IN: mode to check + Bool writePermissions, // IN: callers write permissions + Bool readPermissions); // IN: callers read permissions + #endif // _HGFS_SERVER_POLICY_H_ diff --git a/open-vm-tools/lib/include/hostinfo.h b/open-vm-tools/lib/include/hostinfo.h index ea140c46d..81f797ca7 100644 --- a/open-vm-tools/lib/include/hostinfo.h +++ b/open-vm-tools/lib/include/hostinfo.h @@ -75,6 +75,7 @@ extern Bool Hostinfo_OSIsWow64(void); #endif extern Bool Hostinfo_TouchBackDoor(void); extern Bool Hostinfo_TouchXen(void); +extern char *Hostinfo_HypervisorCPUIDSig(void); #define HGMP_PRIVILEGE 0 #define HGMP_NO_PRIVILEGE 1 @@ -186,5 +187,8 @@ Bool Hostinfo_GetAllCpuid(CPUIDQuery *query); void Hostinfo_LogLoadAverage(void); Bool Hostinfo_GetLoadAverage(uint32 *l); +#ifdef __APPLE__ +size_t Hostinfo_GetKernelZoneElemSize(char const *name); +#endif #endif /* ifndef _HOSTINFO_H_ */ diff --git a/open-vm-tools/lib/include/imageUtil.h b/open-vm-tools/lib/include/imageUtil.h index 13e34eaaf..18e53e7b9 100644 --- a/open-vm-tools/lib/include/imageUtil.h +++ b/open-vm-tools/lib/include/imageUtil.h @@ -49,13 +49,11 @@ EXTERN Bool ImageUtil_ReadPNGBuffer(ImageInfo *image, const unsigned char *imageData, size_t dataLen, int pngReadFlags); -EXTERN Bool ImageUtil_ConstructPNGBuffer(const ImageInfo *image, DynBuf *imageData); -EXTERN Bool ImageUtil_ConstructPNGBufferEx(const ImageInfo *image, - const ImagePngWriteOptions *options, - DynBuf *imageData); +EXTERN Bool ImageUtil_ConstructPNGBuffer(const ImageInfo *image, + const ImagePngWriteOptions *options, + DynBuf *imageData); EXTERN Bool ImageUtil_ConstructBMPBuffer(const ImageInfo *image, DynBuf *imageData); -EXTERN Bool ImageUtil_ConstructBuffer(const ImageInfo *image, ImageType imageType, - DynBuf *imageData); + EXTERN void ImageUtil_FreeImageData(ImageInfo *image); EXTERN Bool ImageUtil_Combine(const ImageInfo *images, const VMPoint *origins, diff --git a/open-vm-tools/lib/include/loglevel_user.h b/open-vm-tools/lib/include/loglevel_user.h index 312b66b9f..c09285f7a 100644 --- a/open-vm-tools/lib/include/loglevel_user.h +++ b/open-vm-tools/lib/include/loglevel_user.h @@ -15,7 +15,7 @@ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * *********************************************************/ - + #ifndef _LOGLEVEL_USER_H_ #define _LOGLEVEL_USER_H_ @@ -70,6 +70,7 @@ LOGLEVEL_VAR(usb), \ LOGLEVEL_VAR(vusbmouse), \ LOGLEVEL_VAR(vusbkeyboard), \ + LOGLEVEL_VAR(vusbhid), \ LOGLEVEL_VAR(hidQueue), \ LOGLEVEL_VAR(pci_1394), \ LOGLEVEL_VAR(1394), \ @@ -216,8 +217,9 @@ LOGLEVEL_VAR(brtalk), /* macWireless and wpa_supplicant */ \ LOGLEVEL_VAR(button), \ LOGLEVEL_VAR(util), \ - LOGLEVEL_VAR(largepage), + LOGLEVEL_VAR(largepage), \ + LOGLEVEL_VAR(guestAppMonitor), LOGLEVEL_EXTENSION_DECLARE(LOGLEVEL_USER); -#endif /* _LOGLEVEL_USER_H_ */ +#endif /* _LOGLEVEL_USER_H_ */ diff --git a/open-vm-tools/lib/include/netutil.h b/open-vm-tools/lib/include/netutil.h index 9bf923fba..c7af8e341 100644 --- a/open-vm-tools/lib/include/netutil.h +++ b/open-vm-tools/lib/include/netutil.h @@ -29,9 +29,20 @@ #define __NETUTIL_H__ #ifdef _WIN32 -#include -#include -#include +/* + * Redefine the WINNT version for this file to be 'LONGHORN' so that we'll get + * the definitions for MIB_IPFORWARDTABLE2 et. al. + */ +# if (_WIN32_WINNT < 0x0600) +# undef _WIN32_WINNT +# define _WIN32_WINNT 0x0600 +# endif + +# include +# include +# include "vmware/iphlpapi_packed.h" +#else +# include #endif #include "vm_basic_types.h" @@ -40,6 +51,16 @@ # include "guestInfo.h" #endif +/* + * Interface types as assigned by IANA. + * See http://www.iana.org/assignments/ianaiftype-mib for more details. + */ + +typedef enum { + IANA_IFTYPE_OTHER = 1, + IANA_IFTYPE_ETHERNETCSMACD = 6, +} IanaIfType; + /* * Modified from iptypes.h... @@ -69,6 +90,9 @@ ULONG NetUtil_GetAdaptersAddresses(ULONG Family, PIP_ADAPTER_ADDRESSES adap_addresses, PULONG SizePointer); +PMIB_IPFORWARDTABLE NetUtilWin32_GetIpForwardTable(void); +PMIB_IPFORWARD_TABLE2 NetUtilWin32_GetIpForwardTable2(void); +void NetUtilWin32_FreeMibTable(PMIB_IPFORWARD_TABLE2); #endif #ifdef N_PLAT_NLM @@ -77,6 +101,15 @@ void NetUtil_MonitorIPStart(void); void NetUtil_MonitorIPStop(void); #endif +#ifdef WIN32 +int NetUtil_InetPToN(int af, const char *src, void *dst); +const char *NetUtil_InetNToP(int af, const void *src, char *dst, + socklen_t size); +#else // ifdef WIN32 +# define NetUtil_InetPToN inet_pton +# define NetUtil_InetNToP inet_ntop +#endif + #if defined(linux) # ifdef DUMMY_NETUTIL /* @@ -101,7 +134,11 @@ EXTERN NetUtilIfTableEntry netUtilIfTable[]; int NetUtil_GetIfIndex(const char *ifName); char *NetUtil_GetIfName(int ifIndex); - #endif // if defined(linux) -#endif +size_t NetUtil_GetHardwareAddress(int ifIndex, // IN + char *hwAddr, // OUT + size_t hwAddrSize, // IN + IanaIfType *ifType); // OUT + +#endif // ifndef _NETUTIL_H_ diff --git a/open-vm-tools/lib/include/preference.h b/open-vm-tools/lib/include/preference.h index 4a7235a14..11b428674 100644 --- a/open-vm-tools/lib/include/preference.h +++ b/open-vm-tools/lib/include/preference.h @@ -37,6 +37,9 @@ extern int64 Preference_GetInt64(int64 defaultvalue, const char *fmt); extern double Preference_GetDouble(double defaultValue, const char *fmt); extern char *Preference_GetString(const char *defaultValue, const char *fmt); extern char *Preference_GetStringPlain(const char *defaultValue, const char *fmt); +extern char *Preference_GetStringEnum(const void *defaultValue, + const char **choices, + const char *name); extern int32 Preference_Generation(void); extern void Preference_Log(void); extern char *Preference_GetPathName(const char *defaultValue, const char *fmt); diff --git a/open-vm-tools/lib/include/safetime.h b/open-vm-tools/lib/include/safetime.h index 6caa5e98d..f387816f1 100644 --- a/open-vm-tools/lib/include/safetime.h +++ b/open-vm-tools/lib/include/safetime.h @@ -50,6 +50,9 @@ #error Use safetime.h instead of time.h, stat.h, and types.h #endif +#undef FMTTIME +#define FMTTIME FMT64"d" + #if (_MSC_VER < 1400) #define _STAT_DEFINED diff --git a/open-vm-tools/lib/include/slashProc.h b/open-vm-tools/lib/include/slashProc.h new file mode 100644 index 000000000..bd3d7b444 --- /dev/null +++ b/open-vm-tools/lib/include/slashProc.h @@ -0,0 +1,44 @@ +/********************************************************* + * Copyright (C) 2009 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. + * + *********************************************************/ + +/** + * @file slashProc.h + */ + +#ifndef _SLASHPROC_H_ +#define _SLASHPROC_H_ + +#include +#include + + +/* + * Global functions + */ + + +EXTERN GHashTable *SlashProcNet_GetSnmp(void); +EXTERN GHashTable *SlashProcNet_GetSnmp6(void); + +EXTERN GPtrArray *SlashProcNet_GetRoute(void); +EXTERN void SlashProcNet_FreeRoute(GPtrArray *); + +EXTERN GPtrArray *SlashProcNet_GetRoute6(void); +EXTERN void SlashProcNet_FreeRoute6(GPtrArray *); + +#endif // ifndef _SLASHPROC_H_ diff --git a/open-vm-tools/lib/include/system.h b/open-vm-tools/lib/include/system.h index 562ae8686..5588a5bf7 100644 --- a/open-vm-tools/lib/include/system.h +++ b/open-vm-tools/lib/include/system.h @@ -78,6 +78,7 @@ typedef struct MonListNode { BOOL System_SetProcessPrivilege(LPCTSTR lpszPrivilege, Bool bEnablePrivilege); int32 System_GetSPVersion(void); Bool System_IsLoginScreenActive(void); +Bool System_IsProcessElevated(void); Bool System_IsScreenSaverActive(void); Bool System_IsScreenSaverRunning(void); Bool System_StartDesktopSwitchThread(DesktopSwitchThreadArgs *args); diff --git a/open-vm-tools/lib/include/unityCommon.h b/open-vm-tools/lib/include/unityCommon.h index fb61dab40..aa0c844b3 100644 --- a/open-vm-tools/lib/include/unityCommon.h +++ b/open-vm-tools/lib/include/unityCommon.h @@ -230,6 +230,8 @@ #define UNITY_RPC_DESKTOP_CONFIG_SET "unity.desktop.config.set" #define UNITY_RPC_DESKTOP_ACTIVE_SET "unity.desktop.active.set" #define UNITY_RPC_WINDOW_DESKTOP_SET "unity.window.desktop.set" +#define UNITY_RPC_WINDOW_STICK "unity.window.stick" +#define UNITY_RPC_WINDOW_UNSTICK "unity.window.unstick" #define GHI_RPC_GUEST_SHELL_ACTION "ghi.guest.shell.action" #define GHI_RPC_SET_GUEST_HANDLER "ghi.guest.handler.set" @@ -744,6 +746,22 @@ desktop where the upper right {1,2} is the currently active desktop. @param[in] UnityWindowId UnityWindowId of window to move @param[in] offset Offset into desktop configuration, as defined by @ref UNITY_RPC_DESKTOP_CONFIG_SET, 0 or greater. + + + @def UNITY_RPC_WINDOW_STICK + @brief "Stick" a window to the screen. + @code + UNITY_RPC_WINDOW_STICK UnityWindowId + @endcode + @param[in] UnityWindowId UnityWindowId of window to stick. + + @def UNITY_RPC_WINDOW_UNSTICK + @brief "Unstick" a window from the screen. + @code + UNITY_RPC_WINDOW_UNSTICK UnityWindowId + @endcode + @param[in] UnityWindowId UnityWindowId of window to unstick. + @} */ diff --git a/open-vm-tools/lib/include/util.h b/open-vm-tools/lib/include/util.h index 6d327cf6e..55abf53c2 100644 --- a/open-vm-tools/lib/include/util.h +++ b/open-vm-tools/lib/include/util.h @@ -81,9 +81,9 @@ EXTERN char *Util_GetMacOSDefaultVMPath(); #endif // __APPLE__ -EXTERN uint32 CRC_Compute(uint8 *buf, int len); -EXTERN uint32 Util_Checksum32(uint32 *buf, int len); -EXTERN uint32 Util_Checksum(uint8 *buf, int len); +EXTERN uint32 CRC_Compute(const uint8 *buf, int len); +EXTERN uint32 Util_Checksum32(const uint32 *buf, int len); +EXTERN uint32 Util_Checksum(const uint8 *buf, int len); EXTERN uint32 Util_Checksumv(void *iov, int numEntries); EXTERN Unicode Util_ExpandString(ConstUnicode fileName); EXTERN void Util_ExitThread(int); diff --git a/open-vm-tools/lib/include/util_shared.h b/open-vm-tools/lib/include/util_shared.h index 172610b60..80b9389fb 100644 --- a/open-vm-tools/lib/include/util_shared.h +++ b/open-vm-tools/lib/include/util_shared.h @@ -74,7 +74,7 @@ UtilCRCMakeTable(void) } static INLINE_SINGLE_CALLER uint32 -UtilCRCUpdate(uint32 crc, uint8 *buf, int len) +UtilCRCUpdate(uint32 crc, const uint8 *buf, int len) { uint32 c = crc; int n; @@ -108,7 +108,7 @@ UtilCRCUpdate(uint32 crc, uint8 *buf, int len) *---------------------------------------------------------------------- */ uint32 -CRC_Compute(uint8 *buf, int len) +CRC_Compute(const uint8 *buf, int len) { return UtilCRCUpdate(0xffffffffL, buf, len) ^ 0xffffffffL; } diff --git a/open-vm-tools/lib/include/vix.h b/open-vm-tools/lib/include/vix.h index 044fba718..ec826a334 100644 --- a/open-vm-tools/lib/include/vix.h +++ b/open-vm-tools/lib/include/vix.h @@ -117,6 +117,7 @@ enum { VIX_E_NEED_KEY = 30, VIX_E_LICENSE = 32, VIX_E_VM_HOST_DISCONNECTED = 34, + VIX_E_AUTHENTICATION_FAIL = 35, /* Handle Errors */ VIX_E_INVALID_HANDLE = 1000, @@ -460,6 +461,10 @@ enum { VIX_PROPERTY_SNAPSHOT_POWERSTATE = 4205, VIX_PROPERTY_SNAPSHOT_IS_REPLAYABLE = 4207, + VIX_PROPERTY_GUEST_SHAREDFOLDERS_SHARES_PATH = 4525, + + /* Virtual machine encryption properties */ + VIX_PROPERTY_VM_ENCRYPTION_PASSWORD = 7001, }; /* @@ -1119,7 +1124,8 @@ VixHandle VixVM_UpgradeVirtualHardware(VixHandle vmHandle, enum { VIX_INSTALLTOOLS_MOUNT_TOOLS_INSTALLER = 0x00, - VIX_INSTALLTOOLS_AUTO_UPGRADE = 0x01 + VIX_INSTALLTOOLS_AUTO_UPGRADE = 0x01, + VIX_INSTALLTOOLS_RETURN_IMMEDIATELY = 0x02 }; VixHandle VixVM_InstallTools(VixHandle vmHandle, diff --git a/open-vm-tools/lib/include/vixCommands.h b/open-vm-tools/lib/include/vixCommands.h index 4f3cd39ca..961696f35 100644 --- a/open-vm-tools/lib/include/vixCommands.h +++ b/open-vm-tools/lib/include/vixCommands.h @@ -94,6 +94,7 @@ enum { VIX_REQUESTMSG_RETURN_ON_INITIATING_TOOLS_UPGRADE = 0x02, VIX_REQUESTMSG_RUN_IN_ANY_VMX_STATE = 0x04, VIX_REQUESTMSG_REQUIRES_INTERACTIVE_ENVIRONMENT = 0x08, + VIX_REQUESTMSG_INCLUDES_AUTH_DATA_V1 = 0x10, }; @@ -398,6 +399,15 @@ struct VixMsgSetVMStateRequest { VixMsgSetVMStateRequest; +typedef +#include "vmware_pack_begin.h" +struct VixMsgAuthDataV1 { + int64 nonce; + uint32 sequenceNumber; + uint8 hashValue[32]; +} +#include "vmware_pack_end.h" +VixMsgAuthDataV1; @@ -1482,6 +1492,17 @@ struct VixCommandMakeSessionKeyResponse { VixCommandMakeSessionKeyResponse; +typedef +#include "vmware_pack_begin.h" +struct VixCommandGenerateNonceResponse { + VixCommandResponseHeader header; + + int64 nonce; +} +#include "vmware_pack_end.h" +VixCommandGenerateNonceResponse; + + enum { VIX_CYPHERTYPE_NONE = 0, VIX_CYPHERTYPE_DEFAULT = 1, @@ -2394,6 +2415,10 @@ enum { VIX_COMMAND_REMOVE_BULK_SNAPSHOT = 172, + VIX_COMMAND_COPY_FILE_FROM_READER_TO_GUEST = 173, + + VIX_COMMAND_GENERATE_NONCE = 174, + /* * HOWTO: Adding a new Vix Command. Step 2a. * @@ -2404,7 +2429,7 @@ enum { * Once a new command is added here, a command info field needs to be added * in bora/lib/foundryMsg. as well. */ - VIX_COMMAND_LAST_NORMAL_COMMAND = 173, + VIX_COMMAND_LAST_NORMAL_COMMAND = 175, VIX_TEST_UNSUPPORTED_TOOLS_OPCODE_COMMAND = 998, VIX_TEST_UNSUPPORTED_VMX_OPCODE_COMMAND = 999, diff --git a/open-vm-tools/lib/include/vm_basic_defs.h b/open-vm-tools/lib/include/vm_basic_defs.h index ae4d0c3db..08f2188fd 100644 --- a/open-vm-tools/lib/include/vm_basic_defs.h +++ b/open-vm-tools/lib/include/vm_basic_defs.h @@ -514,25 +514,6 @@ typedef int pid_t; #endif #endif -/* - * Convenience macro for COMMUNITY_SOURCE - */ -#undef EXCLUDE_COMMUNITY_SOURCE -#ifdef COMMUNITY_SOURCE - #define EXCLUDE_COMMUNITY_SOURCE(x) -#else - #define EXCLUDE_COMMUNITY_SOURCE(x) x -#endif - -#undef COMMUNITY_SOURCE_INTEL_SECRET -#if !defined(COMMUNITY_SOURCE) || defined(INTEL_SOURCE) -/* - * It's ok to include INTEL_SECRET source code for non-commsrc, - * or for drops directed at Intel. - */ - #define COMMUNITY_SOURCE_INTEL_SECRET -#endif - /* * Convenience macros and definitions. Can often be used instead of #ifdef. */ diff --git a/open-vm-tools/lib/include/vm_basic_types.h b/open-vm-tools/lib/include/vm_basic_types.h index 43bc38fac..0034514e9 100644 --- a/open-vm-tools/lib/include/vm_basic_types.h +++ b/open-vm-tools/lib/include/vm_basic_types.h @@ -940,7 +940,21 @@ typedef void * UserVA; #if defined(__FreeBSD__) && (__FreeBSD__ + 0) && ((__FreeBSD__ + 0) >= 5) # define FMTTIME FMTSZ"d" #else -# define FMTTIME "ld" +# if defined(_MSC_VER) +# ifndef _SAFETIME_H_ +# if (_MSC_VER < 1400) || defined(_USE_32BIT_TIME_T) +# define FMTTIME "ld" +# else +# define FMTTIME FMT64"d" +# endif +# else +# ifndef FMTTIME +# error "safetime.h did not define FMTTIME" +# endif +# endif +# else +# define FMTTIME "ld" +# endif #endif /* diff --git a/open-vm-tools/lib/include/vm_product.h b/open-vm-tools/lib/include/vm_product.h index 85e763339..9a35b5e72 100644 --- a/open-vm-tools/lib/include/vm_product.h +++ b/open-vm-tools/lib/include/vm_product.h @@ -134,7 +134,7 @@ #define PRODUCT_VDDK_SHORT_NAME "VDDK" #define PRODUCT_VDDK_NAME MAKE_NAME("VMware Virtual Disk Development Kit") -#define PRODUCT_VDM_CLIENT_NAME MAKE_NAME("VDM Client") +#define PRODUCT_VDM_CLIENT_NAME MAKE_NAME("View Client") #define PRODUCT_VDM_CLIENT_NAME_FOR_LICENSE PRODUCT_VDM_CLIENT_NAME // XXX VMvisor is the underlying technology for possibly several products, @@ -233,7 +233,7 @@ || defined(VMX86_WGS) \ || defined(VMX86_DESKTOP) \ || defined(VMX86_ENTERPRISE_DESKTOP) \ - || defined(VMX86_MUI) \ + || defined(VMX86_MUI) \ || defined(VMX86_API) \ || defined(VMX86_VPX) \ || defined(VMX86_WBC) \ @@ -549,12 +549,12 @@ * For Host Agent (hostd) */ -#define HOST_AGENT_PRODUCT_NAME PRODUCT_NAME " Host Agent" +#define HOST_AGENT_PRODUCT_NAME PRODUCT_NAME " Host Agent" /* Used by bora/vim/lib/vmgina module. * @todo Use this also in /bora/install/msi/InstUtil/desktop/vmInstUtil.cpp * to guarantee that the service is installed with exactly this name. */ -#define HOST_AGENT_SERVICE_NAME "VMwareHostd" +#define HOST_AGENT_SERVICE_NAME "VMwareHostd" #endif /* VM_PRODUCT_H */ diff --git a/open-vm-tools/lib/include/vm_tools_version.h b/open-vm-tools/lib/include/vm_tools_version.h index 7f2397fc3..237bfac2a 100644 --- a/open-vm-tools/lib/include/vm_tools_version.h +++ b/open-vm-tools/lib/include/vm_tools_version.h @@ -893,6 +893,13 @@ typedef uint32 ToolsVersion; #define TOOLS_VERSION_WS70_BETA2_V_MNR 1 #define TOOLS_VERSION_WS70_BETA2_V_BASE 1 +#ifndef RC_INVOKED +#define TOOLS_VERSION_WS70_RC TOOLS_VERSION_TO_UINT(TOOLS_VERSION_WS70_RC_V) +#endif /* RC_INVOKED */ +#define TOOLS_VERSION_WS70_RC_V_MJR 8 +#define TOOLS_VERSION_WS70_RC_V_MNR 1 +#define TOOLS_VERSION_WS70_RC_V_BASE 2 + #ifndef RC_INVOKED #define TOOLS_VERSION_FUSION30_BETA1 TOOLS_VERSION_TO_UINT(TOOLS_VERSION_FUSION30_BETA1_V) #endif /* RC_INVOKED */ @@ -907,10 +914,16 @@ typedef uint32 ToolsVersion; #define TOOLS_VERSION_FUSION30_BETA2_V_MNR 2 #define TOOLS_VERSION_FUSION30_BETA2_V_BASE 1 +#ifndef RC_INVOKED +#define TOOLS_VERSION_FUSION30_RC TOOLS_VERSION_TO_UINT(TOOLS_VERSION_FUSION30_RC_V) +#endif /* RC_INVOKED */ +#define TOOLS_VERSION_FUSION30_RC_V_MJR 8 +#define TOOLS_VERSION_FUSION30_RC_V_MNR 2 +#define TOOLS_VERSION_FUSION30_RC_V_BASE 2 -#define TOOLS_VERSION_CURRENT TOOLS_VERSION_WS70_BETA2 -#define TOOLS_VERSION_CURRENT_STR TOOLS_VERSION_TO_STR(TOOLS_VERSION_WS70_BETA2) -#define TOOLS_VERSION_CURRENT_CSV TOOLS_VERSION_TO_CSV(TOOLS_VERSION_WS70_BETA2) +#define TOOLS_VERSION_CURRENT TOOLS_VERSION_WS70_RC +#define TOOLS_VERSION_CURRENT_STR TOOLS_VERSION_TO_STR(TOOLS_VERSION_WS70_RC) +#define TOOLS_VERSION_CURRENT_CSV TOOLS_VERSION_TO_CSV(TOOLS_VERSION_WS70_RC) /* diff --git a/open-vm-tools/lib/include/vm_version.h b/open-vm-tools/lib/include/vm_version.h index 216ab60cd..a881c916d 100644 --- a/open-vm-tools/lib/include/vm_version.h +++ b/open-vm-tools/lib/include/vm_version.h @@ -90,7 +90,7 @@ #elif defined(VMX86_VCB) #define PRODUCT_VERSION 1,0,0,PRODUCT_BUILD_NUMBER_NUMERIC #elif defined(VMX86_VLICENSE) - #define PRODUCT_VERSION 1,1,0,PRODUCT_BUILD_NUMBER_NUMERIC + #define PRODUCT_VERSION 1,1,2,PRODUCT_BUILD_NUMBER_NUMERIC #else #define PRODUCT_VERSION 3,1,0,PRODUCT_BUILD_NUMBER_NUMERIC #endif @@ -219,7 +219,7 @@ #define FOUNDRY_VERSION "e.x.p" #define FOUNDRY_FILE_VERSION 1,7,0,PRODUCT_BUILD_NUMBER_NUMERIC #define VMLS_VERSION "e.x.p" -#define VLICENSE_VERSION "1.1.0" +#define VLICENSE_VERSION "1.1.2" #define DDK_VERSION "e.x.p" #define VIM_API_VERSION "4.0" #define VIPERL_VERSION "1.1.0" @@ -252,7 +252,7 @@ /* * The current Tools version, derived from vm_tools_version.h. Do not modify this. */ -#define TOOLS_VERSION "2009.07.22" +#define TOOLS_VERSION "2009.08.24" #ifdef VMX86_VPX #define VIM_API_TYPE "VirtualCenter" diff --git a/open-vm-tools/lib/include/vmblock_user.h b/open-vm-tools/lib/include/vmblock_user.h new file mode 100644 index 000000000..13213ee38 --- /dev/null +++ b/open-vm-tools/lib/include/vmblock_user.h @@ -0,0 +1,165 @@ +/********************************************************* + * Copyright (C) 2009 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. + * + *********************************************************/ + +/********************************************************* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of VMware Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission of VMware Inc. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *********************************************************/ + +/********************************************************* + * The contents of this file are subject to the terms of the Common + * Development and Distribution License (the "License") version 1.0 + * and no later version. You may not use this file except in + * compliance with the License. + * + * You can obtain a copy of the License at + * http://www.opensource.org/licenses/cddl1.php + * + * See the License for the specific language governing permissions + * and limitations under the License. + * + *********************************************************/ + +/* + * vmblock_user.h -- + * + * Provides interfaces that allow user level programs to talk to the + * vmblock fs. + */ + +#ifndef _VMBLOCK_USER_H_ +#define _VMBLOCK_USER_H_ + +#include "vm_basic_types.h" +#include "vmblock.h" + +static INLINE int +VMBLOCK_CONTROL_FUSE(int fd, // IN + char op, // IN + const char *path) // IN +{ + /* + * buffer needs room for an operation character and a string with max length + * PATH_MAX - 1. + */ + + char buffer[PATH_MAX]; + size_t pathLength; + + pathLength = strlen(path); + if (pathLength >= PATH_MAX) { + errno = ENAMETOOLONG; + return -1; + } + + buffer[0] = op; + memcpy(buffer + 1, path, pathLength); + + /* + * The lseek is only to prevent the file pointer from overflowing; + * vmblock-fuse ignores the file pointer / offset. Overflowing the file + * pointer causes write to fail: + * http://article.gmane.org/gmane.comp.file-systems.fuse.devel/6648 + * There's also a race condition here where many threads all calling + * VMBLOCK_CONTROL at the same time could have all their seeks executed one + * after the other, followed by all the writes. Again, it's not a problem + * unless the file pointer overflows which is very unlikely with 32 bit + * offsets and practically impossible with 64 bit offsets. + */ + + if (lseek(fd, 0, SEEK_SET) < 0) { + return -1; + } + + if (write(fd, buffer, pathLength + 1) < 0) { + return -1; + } + + return 0; +} + +#if defined(vmblock_fuse) + +#define VMBLOCK_CONTROL(fd, op, path) VMBLOCK_CONTROL_FUSE(fd, op, path) + +#elif defined(linux) + +static INLINE int +VMBLOCK_CONTROL(int fd, int op, const char *path) +{ + return write(fd, path, op); +} + +#elif defined(__FreeBSD__) + +static INLINE int +VMBLOCK_CONTROL(int fd, int cmd, const char *path) +{ + char tpath[MAXPATHLEN]; + size_t pathSize; + + if (path == NULL) { + return -1; + } + + /* + * FreeBSD's ioctl data parameters must be of fixed size. Guarantee a safe + * buffer of size MAXPATHLEN by copying the user's string to one of our own. + */ + pathSize = strlcpy(tpath, path, MAXPATHLEN); + if (pathSize >= sizeof tpath) { + return -1; + } + + return ioctl(fd, cmd, tpath); +} + +#elif defined(sun) + +static INLINE int +VMBLOCK_CONTROL(int fd, int cmd, const char *path) +{ + return ioctl(fd, cmd, path); +} + +#endif + +#endif // _VMBLOCK_USER_H_ diff --git a/open-vm-tools/lib/include/vmtools.h b/open-vm-tools/lib/include/vmtools.h index b33e6372a..694405993 100644 --- a/open-vm-tools/lib/include/vmtools.h +++ b/open-vm-tools/lib/include/vmtools.h @@ -109,6 +109,9 @@ VMTools_ReloadConfig(const gchar *path, GKeyFile **config, time_t *mtime); +void +VMTools_ResetLogging(gboolean cleanDefault); + gboolean VMTools_WriteConfig(const gchar *path, GKeyFile *config, diff --git a/open-vm-tools/lib/include/wiper.h b/open-vm-tools/lib/include/wiper.h index 25d15c842..0efa4bc95 100644 --- a/open-vm-tools/lib/include/wiper.h +++ b/open-vm-tools/lib/include/wiper.h @@ -26,16 +26,16 @@ #ifndef _WIPER_H_ # define _WIPER_H_ - #if defined(_WIN32) && defined(_MSC_VER) #include #endif - #include "vm_basic_types.h" +#include "dbllnklst.h" typedef enum { + PARTITION_UNSUPPORTED = 0, PARTITION_EXT2, PARTITION_EXT3, PARTITION_REISERFS, @@ -52,28 +52,25 @@ typedef enum { typedef struct WiperPartition { unsigned char mountPoint[NATIVE_MAX_PATH]; - /* - * Empty if type is set, otherwise describes why the partition can not be - * wiped - */ - char *comment; - - /* Type of the partition we know how to wipe */ + /* Type of the partition */ WiperPartition_Type type; + /* + * NULL if type is not PARTITION_UNSUPPORTED, otherwise describes + * why the partition can not be wiped. + */ + const char *comment; + #if defined(_WIN32) /* Private flags used by the Win32 implementation */ DWORD flags; #endif -#if defined(N_PLAT_NLM) - unsigned long volumeNumber; -#endif + DblLnkLst_Links link; } WiperPartition; typedef struct WiperPartition_List { - WiperPartition *partitions; - unsigned int size; + DblLnkLst_Links link; } WiperPartition_List; typedef struct WiperInitData { @@ -83,15 +80,16 @@ typedef struct WiperInitData { } WiperInitData; Bool Wiper_Init(WiperInitData *clientData); -WiperPartition_List *WiperPartition_Open(void); +Bool WiperPartition_Open(WiperPartition_List *pl); void WiperPartition_Close(WiperPartition_List *pl); -WiperPartition *SingleWiperPartition_Open(const char *mntpt); -void SingleWiperPartition_Close(WiperPartition *pl); +WiperPartition *WiperSinglePartition_Allocate(void); +WiperPartition *WiperSinglePartition_Open(const char *mntpt); +void WiperSinglePartition_Close(WiperPartition *); -unsigned char *WiperSinglePartition_GetSpace(const WiperPartition *p, - uint64 *free, - uint64 *total); +unsigned char *WiperSinglePartition_GetSpace(const WiperPartition *p, + uint64 *free, + uint64 *total); /* External definition of the wiper state */ struct Wiper_State; diff --git a/open-vm-tools/lib/include/x86cpuid.h b/open-vm-tools/lib/include/x86cpuid.h index 223060392..141957129 100644 --- a/open-vm-tools/lib/include/x86cpuid.h +++ b/open-vm-tools/lib/include/x86cpuid.h @@ -48,6 +48,7 @@ #include "includeCheck.h" #include "vm_basic_types.h" +#include "community_source.h" /* * The linux kernel's ptrace.h stupidly defines the bare @@ -107,10 +108,6 @@ CPUIDQuery; * during power-on/migration. Any level which is marked as FALSE here * *must* have all field masks defined as IGNORE in CPUID_FIELD_DATA. * A static assert in lib/cpuidcompat/cpuidcompat.c will check this. - * - * IMPORTANT: WHEN ADDING A NEW FIELD TO THE CACHED LEVELS, make sure - * you update vmcore/vmm/cpu/priv.c:Priv_CPUID() and vmcore/vmm64/bt/ - * cpuid_shared.S (and geninfo) to include the new level. */ #define CPUID_CACHED_LEVELS \ @@ -121,6 +118,7 @@ CPUIDQuery; CPUIDLEVEL(FALSE,410, 0x40000010) \ CPUIDLEVEL(FALSE, 80, 0x80000000) \ CPUIDLEVEL(TRUE, 81, 0x80000001) \ + CPUIDLEVEL(FALSE, 87, 0x80000007) \ CPUIDLEVEL(FALSE, 88, 0x80000008) \ CPUIDLEVEL(TRUE, 8A, 0x8000000A) @@ -128,8 +126,7 @@ CPUIDQuery; CPUIDLEVEL(FALSE, 4, 4) \ CPUIDLEVEL(FALSE, 6, 6) \ CPUIDLEVEL(FALSE, A, 0xA) \ - CPUIDLEVEL(FALSE, 86, 0x80000006) \ - CPUIDLEVEL(FALSE, 87, 0x80000007) \ + CPUIDLEVEL(FALSE, 86, 0x80000006) #define CPUID_ALL_LEVELS \ CPUID_CACHED_LEVELS \ @@ -143,6 +140,11 @@ typedef enum { CPUID_NUM_LEVELS } CpuidLevels; + +/* SVM CPUID feature leaf */ +#define CPUID_SVM_FEATURES 0x8000000a + + /* * CPUID result registers */ @@ -659,6 +661,7 @@ FIELD_FUNC(MWAIT_C4_SUBSTATE, CPUID_INTEL_ID5EDX_MWAIT_C4_SUBSTATE) #define CPUID_MODEL_NEHALEM_1A 0x1a // Nehalem / Gainestown #define CPUID_MODEL_ATOM_1C 0x1c // Silverthorne / Diamondville #define CPUID_MODEL_CORE_1D 0x1d // Dunnington +#define CPUID_MODEL_NEHALEM_1E 0x1e // Lynnfield #define CPUID_MODEL_PIII_07 7 #define CPUID_MODEL_PIII_08 8 @@ -789,9 +792,13 @@ CPUID_UARCH_IS_NEHALEM(uint32 v) // IN: %eax from CPUID with %eax=1. return CPUID_FAMILY_IS_P6(v) && ( + effectiveModel == CPUID_MODEL_NEHALEM_1E || effectiveModel == CPUID_MODEL_NEHALEM_1A); } + + + static INLINE Bool CPUID_FAMILY_IS_K7(uint32 _eax) { diff --git a/open-vm-tools/lib/include/xdrutil.h b/open-vm-tools/lib/include/xdrutil.h index 4e051f078..d64be4d36 100644 --- a/open-vm-tools/lib/include/xdrutil.h +++ b/open-vm-tools/lib/include/xdrutil.h @@ -58,11 +58,20 @@ * Wrapper for XdrUtil_ArrayAppend that automatically populates the arguments * from a given XDR array. */ -#define XDRUTIL_ARRAYAPPEND(ptr, field, cnt) \ - XdrUtil_ArrayAppend((void **) &(ptr)->field.field##_val, \ - &(ptr)->field.field##_len, \ - sizeof *(ptr)->field.field##_val, \ - (cnt)); +#ifdef __GNUC__ +# define XDRUTIL_ARRAYAPPEND(ptr, field, cnt) \ + (typeof ((ptr)->field.field##_val)) \ + XdrUtil_ArrayAppend((void **) &(ptr)->field.field##_val, \ + &(ptr)->field.field##_len, \ + sizeof *(ptr)->field.field##_val, \ + (cnt)) +#else +# define XDRUTIL_ARRAYAPPEND(ptr, field, cnt) \ + XdrUtil_ArrayAppend((void **) &(ptr)->field.field##_val, \ + &(ptr)->field.field##_len, \ + sizeof *(ptr)->field.field##_val, \ + (cnt)) +#endif void * XdrUtil_ArrayAppend(void **array, u_int *arrayLen, size_t elemSz, u_int elemCnt); diff --git a/open-vm-tools/lib/misc/codesetOld.c b/open-vm-tools/lib/misc/codesetOld.c index 09cf41803..e6fccb2dd 100644 --- a/open-vm-tools/lib/misc/codesetOld.c +++ b/open-vm-tools/lib/misc/codesetOld.c @@ -76,6 +76,10 @@ static const char nul[] = {'\0', '\0'}; static const wchar_t nul = L'\0'; #endif +#ifndef USE_ICONV +static Bool CodeSetOldIso88591ToUtf8Db(char const *bufIn, size_t sizeIn, + unsigned int flags, DynBuf *db); +#endif /* *----------------------------------------------------------------------------- @@ -103,35 +107,35 @@ CodeSetOldGetUtf8(const char *string, // IN: string uint8 *e; uint32 c; int len; - ASSERT(string < end); c = *p; if (c < 0x80) { - // ASCII + // ASCII: U+0000 - U+007F: 1 byte of UTF-8. len = 1; goto out; } - if (c < 0xc2) { + if ((c < 0xc2) || (c > 0xf4)) { // 0x81 to 0xbf are not valid first bytes // 0xc0 and 0xc1 cannot appear in UTF-8, see below + // leading char can not be > 0xf4, illegal as well return 0; } if (c < 0xe0) { + // U+0080 - U+07FF: 2 bytes of UTF-8. c -= 0xc0; len = 2; - } else if (c <= 0xf0) { + } else if (c < 0xf0) { + // U+0800 - U+FFFF: 3 bytes of UTF-8. c -= 0xe0; len = 3; - } else if (c <= 0xf8) { + } else { + // U+10000 - U+10FFFF: 4 bytes of UTF-8. c -= 0xf0; len = 4; - } else { - // bad first byte - return 0; } if ((e = p + len) > (uint8 *) end) { @@ -1171,6 +1175,14 @@ CodeSetOld_GenericToGenericDb(char const *codeIn, // IN } else { goto exit; } + } else if (STRING_ENCODING_ISO_8859_1 == encIn) { + if (STRING_ENCODING_UTF8 == encOut) { + if (!CodeSetOldIso88591ToUtf8Db(bufIn, sizeIn, flags, db)) { + goto exit; + } + } else { + goto exit; + } } else { goto exit; } @@ -2085,6 +2097,50 @@ CodeSetOld_Utf8ToAsciiDb(char const *bufIn, // IN } +#ifndef USE_ICONV +/* + *----------------------------------------------------------------------------- + * + * CodeSetOldIso88591ToUtf8Db -- + * + * Convert ISO-8859-1 to UTF-8 + * + * Results: + * On success, TRUE and conversion result appended to db. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static Bool +CodeSetOldIso88591ToUtf8Db(char const *bufIn, // IN + size_t sizeIn, // IN + unsigned int flags, // IN + DynBuf *db) // OUT +{ + size_t i; + size_t last = 0; + + for (i = 0; i < sizeIn; i++) { + unsigned int c = (unsigned char)bufIn[i]; + if (UNLIKELY(c >= 0x80)) { + unsigned char buf[2]; + + buf[0] = 0xC0 | (c >> 6); + buf[1] = 0x80 | (c & 0x3F); + DynBuf_Append(db, bufIn + last, i - last); + DynBuf_Append(db, buf, sizeof buf); + last = i + 1; + } + } + DynBuf_Append(db, bufIn + last, i - last); + return TRUE; +} +#endif + + #if defined(_WIN32) /* *----------------------------------------------------------------------------- diff --git a/open-vm-tools/lib/misc/hostinfoPosix.c b/open-vm-tools/lib/misc/hostinfoPosix.c index e57491ee0..9fb593a91 100644 --- a/open-vm-tools/lib/misc/hostinfoPosix.c +++ b/open-vm-tools/lib/misc/hostinfoPosix.c @@ -51,6 +51,7 @@ #include #include #include +#include #elif defined(__FreeBSD__) #if !defined(RLIMIT_AS) # if defined(RLIMIT_VMEM) @@ -123,7 +124,7 @@ static Bool hostinfoOSVersionInitialized; #if defined(__APPLE__) #define SYS_NMLN _SYS_NAMELEN #endif -static int hostinfoOSVersion[3]; +static int hostinfoOSVersion[4]; static char hostinfoOSVersionString[SYS_NMLN]; #define DISTRO_BUF_SIZE 255 @@ -226,7 +227,7 @@ HostinfoOSVersionInit(void) Str_Strcpy(hostinfoOSVersionString, u.release, SYS_NMLN); - ASSERT(ARRAYSIZE(hostinfoOSVersion) >= 3); + ASSERT(ARRAYSIZE(hostinfoOSVersion) >= 4); if (sscanf(u.release, "%d.%d.%d%s", &hostinfoOSVersion[0], &hostinfoOSVersion[1], &hostinfoOSVersion[2], extra) < 1) { @@ -235,6 +236,11 @@ HostinfoOSVersionInit(void) NOT_IMPLEMENTED(); } + /* If there is a 4th number, use it, otherwise use 0. */ + if (sscanf(extra, ".%d%*s", &hostinfoOSVersion[3]) < 1) { + hostinfoOSVersion[3] = 0; + } + hostinfoOSVersionInitialized = TRUE; } @@ -1654,10 +1660,6 @@ Hostinfo_ResetProcessState(const int *keepFds, // IN: int s, fd; struct sigaction sa; struct rlimit rlim; -#ifdef __linux__ - int err; - uid_t euid; -#endif /* * Disable itimers before resetting the signal handlers. @@ -1700,15 +1702,21 @@ Hostinfo_ResetProcessState(const int *keepFds, // IN: #ifdef __linux__ /* * Drop iopl to its default value. + * iopl() is not implemented in userworlds */ - euid = Id_GetEUid(); - /* At this point, _unless we are running as root_, we shouldn't have root - privileges --hpreg */ - ASSERT(euid != 0 || getuid() == 0); - Id_SetEUid(0); - err = iopl(0); - Id_SetEUid(euid); - ASSERT_NOT_IMPLEMENTED(err == 0); + if (!vmx86_server) { + int err; + uid_t euid; + + euid = Id_GetEUid(); + /* At this point, _unless we are running as root_, we shouldn't have root + privileges --hpreg */ + ASSERT(euid != 0 || getuid() == 0); + Id_SetEUid(0); + err = iopl(0); + Id_SetEUid(euid); + ASSERT_NOT_IMPLEMENTED(err == 0); + } #endif } @@ -2349,3 +2357,155 @@ Hostinfo_Execute(const char *command, // IN: return 0; } } + + +#ifdef __APPLE__ +/* + *----------------------------------------------------------------------------- + * + * Hostinfo_GetKernelZoneElemSize -- + * + * Retrieve the size of the elements in a named kernel zone. + * + * We used to do it like zprint (see + * darwinsource-10.4.5/system_cmds-336.10/zprint.tproj/zprint.c::main()), + * i.e. by calling host_zone_info(), but there are 3 problems with that: + * + * 1) mach/mach_host.defs defines both arrays passed to host_zone_info() + * as 'out' parameters, but the implementation of the function in + * xnu-792.13.8/osfmk/kern/zalloc.c clearly expects them as 'inout' + * parameters. This issue is confirmed in practice: the input values + * passed by the user process are ignored. Now comes the scary part: is + * the input of the kernel function deterministically invalid, or is it + * some non-deterministic garbage (in which case the user process can + * corrupt its address space)? The answer is in the Mach IPC code. A + * cursory kernel debugging session seems to imply that the input + * pointer values are garbage, but the input size values are always 0. + * So the function seems safe to use in practice. + * + * 2) Starting with Mac OS 10.6, host_zone_info() always returns + * KERN_NOT_SUPPORTED when the sizes of the user and kernel virtual + * address spaces (32-bit or 64-bit) do not match. Was bug 377049. + * + * 3) Apple broke the ABI: For 64-bit code, the 'zone_info.zi_*_size' + * fields are 32-bit in the Mac OS 10.5 SDK, but 64-bit in the Mac OS + * 10.6 SDK. So a 64-bit VMX compiled against the Mac OS 10.5 SDK works + * with the Mac OS 10.5 (32-bit) kernel but fails with the Mac OS 10.6 + * 64-bit kernel. + * + * So now we just let Apple deal with their own mess: we invoke zprint, + * and we parse its non-localized output. Should Apple stop shipping + * zprint, we can always ship our own replacement for it. + * + * Results: + * On success: the size (in bytes) > 0. + * On failure: 0. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +size_t +Hostinfo_GetKernelZoneElemSize(char const *name) // IN: Kernel zone name +{ + size_t retval = 0; + struct { + size_t retval; + } volatile *shared; + pid_t child; + pid_t pid; + + /* + * popen(3) incorrectly executes the shell with the identity of the calling + * process, ignoring a potential per-thread identity. And starting with + * Mac OS 10.6 it is even worse: if there is a per-thread identity, popen(3) + * removes it! + * + * So we run this code in a separate process which runs with the same + * identity as the current thread. + */ + + shared = mmap(NULL, sizeof *shared, PROT_READ | PROT_WRITE, + MAP_ANON | MAP_SHARED, -1, 0); + if (shared == (void *)-1) { + Warning("%s: mmap error %d.\n", __FUNCTION__, errno); + return retval; + } + + // In case the child is terminated before it can set it. + shared->retval = retval; + + child = fork(); + if (child == (pid_t)-1) { + Warning("%s: fork error %d.\n", __FUNCTION__, errno); + munmap((void *)shared, sizeof *shared); + return retval; + } + + // This executes only in the child process. + if (!child) { + size_t nameLen; + FILE *stream; + Bool parsingProperties = FALSE; + + ASSERT(name); + + nameLen = strlen(name); + ASSERT(nameLen && *name != '\t'); + + stream = popen("/usr/bin/zprint -C", "r"); + if (!stream) { + Warning("%s: popen error %d.\n", __FUNCTION__, errno); + exit(EXIT_SUCCESS); + } + + for (;;) { + char *line; + size_t lineLen; + + if (StdIO_ReadNextLine(stream, &line, 0, &lineLen) != StdIO_Success) { + break; + } + + if (parsingProperties) { + if ( // Not a property line anymore. Property not found. + lineLen < 1 || memcmp(line, "\t", 1) + // Property found. + || sscanf(line, " elem_size: %"FMTSZ"u bytes", + &shared->retval) == 1) { + free(line); + break; + } + } else if (!( lineLen < nameLen + 6 + || memcmp(line, name, nameLen) + || memcmp(line + nameLen, " zone:", 6))) { + // Zone found. + parsingProperties = TRUE; + } + + free(line); + } + + pclose(stream); + exit(EXIT_SUCCESS); + } + + /* + * This executes only in the parent process. + * Wait for the child to terminate, and return its retval. + */ + + do { + int status; + + pid = waitpid(child, &status, 0); + } while (pid == -1 && errno == EINTR); + ASSERT_NOT_IMPLEMENTED(pid == child); + + retval = shared->retval; + munmap((void *)shared, sizeof *shared); + return retval; +} +#endif /* __APPLE__ */ diff --git a/open-vm-tools/lib/netUtil/netUtilLinux.c b/open-vm-tools/lib/netUtil/netUtilLinux.c index f1175cb8a..399caefab 100644 --- a/open-vm-tools/lib/netUtil/netUtilLinux.c +++ b/open-vm-tools/lib/netUtil/netUtilLinux.c @@ -57,6 +57,7 @@ #include #include #include +#include // for ARPHRD_ETHER #if defined(__FreeBSD__) || defined(__APPLE__) #include "ifaddrs.h" @@ -430,4 +431,60 @@ NetUtil_GetIfName(int ifIndex) // IN: interface index } # endif // ifdef DUMMY_NETUTIL + +/* + *----------------------------------------------------------------------------- + * + * NetUtil_GetHardwareAddress -- + * + * Given an interface name, return its hardware/link layer address. + * + * Results: + * Returns TRUE and populates hwAddr on success. + * Returns FALSE on failure. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +size_t +NetUtil_GetHardwareAddress(int ifIndex, // IN + char *hwAddr, // OUT + size_t hwAddrSize, // IN + IanaIfType *ifType) // OUT +{ + struct ifreq ifreq; + int fd = -1; + size_t ret = 0; + + if (hwAddrSize < IFHWADDRLEN) { + return FALSE; + } + + ASSERT(sizeof ifreq.ifr_name >= IF_NAMESIZE); + + memset(&ifreq, 0, sizeof ifreq); + if (if_indextoname(ifIndex, ifreq.ifr_name) == NULL) { + return FALSE; + } + + if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + return FALSE; + } + + if (ioctl(fd, SIOCGIFHWADDR, &ifreq) == 0 && + ifreq.ifr_hwaddr.sa_family == ARPHRD_ETHER) { + memcpy(hwAddr, ifreq.ifr_hwaddr.sa_data, IFHWADDRLEN); + *ifType = IANA_IFTYPE_ETHERNETCSMACD; + ret = IFHWADDRLEN; + } + + close(fd); + + return ret; +} + + #endif // if defined(linux) diff --git a/open-vm-tools/lib/raster/rasterConv.c b/open-vm-tools/lib/raster/rasterConv.c index a5e47465c..cc49d3624 100644 --- a/open-vm-tools/lib/raster/rasterConv.c +++ b/open-vm-tools/lib/raster/rasterConv.c @@ -257,7 +257,8 @@ Raster_GetBPPDepth(uint32 depth, uint32 bpp) * None * * Side effects: - * None + * If converting from a lower true-color depth to 32-bpp, fills the + * alpha values of the destination rectangle to 0xFF. * *---------------------------------------------------------------------- */ @@ -812,7 +813,7 @@ RasterConvertShortTo24(uint8 *tof, uint32 line_increment, * None * * Side effects: - * None + * Fills the alpha values of the destination rectangle to 0xFF. * *---------------------------------------------------------------------- */ @@ -842,7 +843,8 @@ RasterConvertShortTo32(uint8 *tof, uint32 line_increment, for (i=0; i> redShift1) | ((pix & redMask) >> redShift2)) << 16)) | (GREENMASK_32 & @@ -968,7 +970,7 @@ RasterConvert24toShort(uint8 *tof, uint32 line_increment, * None * * Side effects: - * None + * Fills the alpha values of the destination rectangle to 0xFF. * *---------------------------------------------------------------------- */ @@ -995,7 +997,8 @@ RasterConvert24to32(uint8 *tof, uint32 line_increment, uint8 blue = srcptr[k++]; uint8 green = srcptr[k++]; uint8 red = srcptr[k++]; - dstptr[j] = ((red << 16) & REDMASK_32) | + dstptr[j] = (0xFF << 24) | + ((red << 16) & REDMASK_32) | ((green << 8) & GREENMASK_32) | (blue & BLUEMASK_32); } @@ -1258,7 +1261,7 @@ RasterConvertIndexto24(uint8 *tof, uint32 line_increment, * None * * Side effects: - * None + * None * *---------------------------------------------------------------------- */ diff --git a/open-vm-tools/lib/rpcChannel/rpcChannel.c b/open-vm-tools/lib/rpcChannel/rpcChannel.c index 65811726d..a68023ef8 100644 --- a/open-vm-tools/lib/rpcChannel/rpcChannel.c +++ b/open-vm-tools/lib/rpcChannel/rpcChannel.c @@ -23,6 +23,7 @@ */ #include +#include "vm_assert.h" #include "dynxdr.h" #include "rpcChannelInt.h" #include "str.h" @@ -348,7 +349,7 @@ RpcChannel_Dispatch(RpcInData *data) status = rpc->callback(data); } - g_assert(data->result != NULL); + ASSERT(data->result != NULL); exit: data->name = NULL; @@ -481,9 +482,9 @@ void RpcChannel_RegisterCallback(RpcChannel *chan, RpcChannelCallback *rpc) { - g_assert(rpc->name != NULL && strlen(rpc->name) > 0); - g_assert(rpc->callback); - g_assert(rpc->xdrIn == NULL || rpc->xdrInSize > 0); + ASSERT(rpc->name != NULL && strlen(rpc->name) > 0); + ASSERT(rpc->callback); + ASSERT(rpc->xdrIn == NULL || rpc->xdrInSize > 0); if (chan->rpcs == NULL) { chan->rpcs = g_hash_table_new(g_str_hash, g_str_equal); } diff --git a/open-vm-tools/lib/slashProc/Makefile.am b/open-vm-tools/lib/slashProc/Makefile.am new file mode 100644 index 000000000..f7fde2f34 --- /dev/null +++ b/open-vm-tools/lib/slashProc/Makefile.am @@ -0,0 +1,27 @@ +################################################################################ +### Copyright 2007 VMware, Inc. All rights reserved. +### +### This program is free software; you can redistribute it and/or modify +### it under the terms of version 2 of the GNU General Public License as +### published by the Free Software Foundation. +### +### 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 +### GNU General Public License for more details. +### +### You should have received a copy of the GNU 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 +################################################################################ + +noinst_LTLIBRARIES = libSlashProc.la + +libSlashProc_la_SOURCES = +libSlashProc_la_SOURCES += net.c + +libSlashProc_la_CPPFLAGS = +libSlashProc_la_CPPFLAGS += @GLIB2_CPPFLAGS@ + +AM_CFLAGS = $(DNET_CPPFLAGS) + diff --git a/open-vm-tools/lib/slashProc/net.c b/open-vm-tools/lib/slashProc/net.c new file mode 100644 index 000000000..ace98005e --- /dev/null +++ b/open-vm-tools/lib/slashProc/net.c @@ -0,0 +1,888 @@ +/********************************************************* + * Copyright (C) 2009 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. + * + *********************************************************/ + +/** + * @file net.c + * + * Parses assorted /proc/net nodes. + */ + + +#include +#include +#include +#include + +#include +#include + +#include "vmware.h" +#include "panic.h" +#include "slashProc.h" +#include "slashProcNetInt.h" +#include "netutil.h" + + +/* + * Local data. + */ + + +#define PROC_NET_SNMP "/proc/net/snmp" +#define PROC_NET_SNMP6 "/proc/net/snmp6" +#define PROC_NET_ROUTE "/proc/net/route" +#define PROC_NET_ROUTE6 "/proc/net/ipv6_route" + + +/** + * @brief Evaluate an expression with a regular expression match. + * + * Convenience wrapper to fetch a regular expression match result, evaluate + * it as an argument in some expression, and then free it. + * + * @param[in] matchInfo GMatchInfo RE context. + * @param[in] matchIndex Match index. + * @param[in] expr Expression to evaluate. Must contain @c MATCH as + * placeholder where matched value will be inserted. + */ +#define MATCHEXPR(matchInfo, matchIndex, expr) do { \ + gchar *MATCH = g_match_info_fetch(matchInfo, matchIndex); \ + expr; \ + g_free(MATCH); \ +} while(0) + + +/** + * Override-able @c /proc/net/snmp path. Useful for debugging. + */ +static const char *pathToNetSnmp = PROC_NET_SNMP; + + +/** + * Override-able @c /proc/net/snmp6 path. Useful for debugging. + */ +static const char *pathToNetSnmp6 = PROC_NET_SNMP6; + + +/** + * Override-able @c /proc/net/route path. Useful for debugging. + */ +static const char *pathToNetRoute = PROC_NET_ROUTE; + + +/** + * Override-able @c /proc/net/ipv6_route path. Useful for debugging. + */ +static const char *pathToNetRoute6 = PROC_NET_ROUTE6; + + +/* + * Private function prototypes. + */ + +static void Ip6StringToIn6Addr(const char *ip6String, + struct in6_addr *in6_addr); +static guint64 MatchToGuint64(const GMatchInfo *matchInfo, + const gint matchIndex, + gint base); + + +/* + * Library private functions. + */ + + +#ifdef VMX86_DEVEL +/* + ****************************************************************************** + * SlashProcNetSetPathSnmp -- */ /** + * + * @brief Overrides @ref pathToNetSnmp. Useful for debugging. + * + * @param[in] newPathToNetSnmp New path to used in place of @ref PROC_NET_SNMP. + * If @c NULL, @ref pathToNewSnmp reverts to @ref + * PROC_NET_SNMP. + * + ****************************************************************************** + */ + +void +SlashProcNetSetPathSnmp(const char *newPathToNetSnmp) +{ + pathToNetSnmp = newPathToNetSnmp ? newPathToNetSnmp : PROC_NET_SNMP; +} + + +/* + ****************************************************************************** + * SlashProcNetSetPathSnmp6 -- */ /** + * + * @brief Overrides @ref pathToNetSnmp6. Useful for debugging. + * + * @sa SlashProcNetSetPathSnmp + * + ****************************************************************************** + */ + +void +SlashProcNetSetPathSnmp6(const char *newPathToNetSnmp6) +{ + pathToNetSnmp6 = newPathToNetSnmp6 ? newPathToNetSnmp6 : PROC_NET_SNMP6; +} + + +/* + ****************************************************************************** + * SlashProcNetSetPathRoute -- */ /** + * + * @brief Overrides @ref pathToNetRoute. Useful for debugging. + * + * @sa SlashProcNetSetPathSnmp + * + ****************************************************************************** + */ + +void +SlashProcNetSetPathRoute(const char *newPathToNetRoute) +{ + pathToNetRoute = newPathToNetRoute ? newPathToNetRoute : PROC_NET_ROUTE; +} + + +/* + ****************************************************************************** + * SlashProcNetSetPathRoute6 -- */ /** + * + * @brief Overrides @ref pathToNetRoute6. Useful for debugging. + * + * @sa SlashProcNetSetPathSnmp + * + ****************************************************************************** + */ + +void +SlashProcNetSetPathRoute6(const char *newPathToNetRoute6) +{ + pathToNetRoute6 = newPathToNetRoute6 ? newPathToNetRoute6 : PROC_NET_ROUTE6; +} +#endif // ifdef VMX86_DEVEL + + +/* + * Library public functions. + */ + + +/* + ****************************************************************************** + * SlashProcNet_GetSnmp -- */ /** + * + * @brief Reads @ref pathToNetSnmp and returns contents as a + * GHashTable(gchar *key, guint64 *value). + * + * Example usage: + * @code + * GHashTable *netSnmp = SlashProcNet_GetSnmp(); + * guint64 *inDiscards = g_hash_table_lookup(netSnmp, "IpInDiscards"); + * @endcode + * + * @note Caller should free the returned @c GHashTable with + * @c g_hash_table_destroy. + * @note This routine creates persistent GLib GRegexs. + * + * @return On failure, NULL. On success, a valid @c GHashTable. + * @todo Provide a case-insensitive key comparison function. + * @todo Consider init/cleanup routines to not "leak" GRegexs. + * + ****************************************************************************** + */ + +GHashTable * +SlashProcNet_GetSnmp(void) +{ + GHashTable *myHashTable = NULL; + GIOChannel *myChannel = NULL; + GIOStatus keyIoStatus; + GIOStatus valIoStatus; + gchar *myKeyLine = NULL; + gchar *myValLine = NULL; + Bool parseError = FALSE; + int fd = -1; + + static GRegex *myKeyRegex = NULL; + static GRegex *myValRegex = NULL; + + if (myKeyRegex == NULL) { + myKeyRegex = g_regex_new("^(\\w+): (\\w+ )*(\\w+)$", G_REGEX_OPTIMIZE, + 0, NULL); + myValRegex = g_regex_new("^(\\w+): (-?\\d+ )*(-?\\d+)$", G_REGEX_OPTIMIZE, + 0, NULL); + ASSERT(myKeyRegex); + ASSERT(myValRegex); + } + + if ((fd = g_open(pathToNetSnmp, O_RDONLY)) == -1) { + return NULL; + } + + myChannel = g_io_channel_unix_new(fd); + + myHashTable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + + /* + * Expected format: + * + * pfx0: key0 key1 key2 ... keyN + * pfx0: val0 val1 val2 ... valN + * ... + * pfxN: ... + */ + + while ((keyIoStatus = g_io_channel_read_line(myChannel, &myKeyLine, NULL, NULL, + NULL)) == G_IO_STATUS_NORMAL && + (valIoStatus = g_io_channel_read_line(myChannel, &myValLine, NULL, NULL, + NULL)) == G_IO_STATUS_NORMAL) { + + GMatchInfo *keyMatchInfo = NULL; + GMatchInfo *valMatchInfo = NULL; + + gchar **myKeys = NULL; + gchar **myVals = NULL; + + gchar **myKey = NULL; + gchar **myVal = NULL; + + gchar *keyPrefix = NULL; + gchar *valPrefix = NULL; + + /* + * Per format above, we expect a pair of lines with a matching prefix. + */ + { + if (!g_regex_match(myKeyRegex, myKeyLine, 0, &keyMatchInfo) || + !g_regex_match(myValRegex, myValLine, 0, &valMatchInfo)) { + parseError = TRUE; + goto badIteration; + } + + keyPrefix = g_match_info_fetch(keyMatchInfo, 1); + valPrefix = g_match_info_fetch(valMatchInfo, 1); + + ASSERT(keyPrefix); + ASSERT(valPrefix); + + if (strcmp(keyPrefix, valPrefix)) { + parseError = TRUE; + goto badIteration; + } + } + + myKeys = g_strsplit(myKeyLine, " ", 0); + myVals = g_strsplit(myValLine, " ", 0); + + /* + * Iterate over the columns, combining the column keys with the prefix + * to form the new key name. (I.e., "Ip: InDiscards" => "IpInDiscards".) + */ + for (myKey = &myKeys[1], myVal = &myVals[1]; + *myKey && *myVal; + myKey++, myVal++) { + gchar *hashKey; + guint64 *myIntVal = NULL; + + hashKey = g_strjoin(NULL, keyPrefix, *myKey, NULL); + g_strstrip(hashKey); + + /* + * By virtue of having matched the above regex, this conversion + * must hold. + */ + myIntVal = g_new(guint64, 1); + *myIntVal = g_ascii_strtoull(*myVal, NULL, 10); + + /* + * If our input contains duplicate keys, which I really don't see + * happening, the latter value overrides the former. + * + * NB: myHashTable claims ownership of hashKey. + */ + g_hash_table_insert(myHashTable, hashKey, myIntVal); + } + + /* + * Make sure the column counts matched. If we succeeded, both pointers + * should now be NULL. + */ + if (*myKey || *myVal) { + parseError = TRUE; + } + +badIteration: + g_match_info_free(keyMatchInfo); + g_match_info_free(valMatchInfo); + + g_free(keyPrefix); + g_free(valPrefix); + + g_strfreev(myKeys); + g_strfreev(myVals); + + g_free(myKeyLine); + g_free(myValLine); + myKeyLine = NULL; + myValLine = NULL; + + if (parseError) { + break; + } + } + + /* + * Error conditions: + * Hash table empty: Unable to parse any input. + * myKeyLine != NULL: Failed to read "key" and "value" lines during + * same loop iteration. + * parseError == TRUE: See loop body above. + */ + if (keyIoStatus == G_IO_STATUS_ERROR || + valIoStatus == G_IO_STATUS_ERROR || + g_hash_table_size(myHashTable) == 0 || + parseError) { + g_hash_table_destroy(myHashTable); + myHashTable = NULL; + } + + g_free(myKeyLine); + g_free(myValLine); + myKeyLine = NULL; + myValLine = NULL; + + close(fd); + + g_free(myChannel); + + return myHashTable; +} + + +/* + ****************************************************************************** + * SlashProcNet_GetSnmp6 -- */ /** + * + * @brief Reads @ref pathToNetSnmp6 and returns contents as a + * GHashTable(gchar *key, guint64 *value). + * + * Example usage: + * @code + * GHashTable *netSnmp6 = SlashProcNet_GetSnmp6(); + * guint64 *raw6Discards = g_hash_table_lookup(netSnmp6, "Ip6InDiscards"); + * @endcode + * + * @note Caller should free the returned @c GHashTable with + * @c g_hash_table_destroy. + * @note This routine creates persistent GLib GRegexs. + * + * @return On failure, NULL. On success, a valid @c GHashTable. + * @todo Provide a case-insensitive key comparison function. + * @todo Consider init/cleanup routines to not "leak" GRegexs. + * + ****************************************************************************** + */ + +GHashTable * +SlashProcNet_GetSnmp6(void) +{ + GHashTable *myHashTable = NULL; + GIOChannel *myChannel = NULL; + GIOStatus ioStatus; + gchar *myInputLine = NULL; + Bool parseError = FALSE; + int fd = -1; + + static GRegex *myRegex = NULL; + + if (myRegex == NULL) { + myRegex = g_regex_new("^(\\w+)\\s+(-?\\d+)\\s*$", G_REGEX_OPTIMIZE, + 0, NULL); + ASSERT(myRegex); + } + + if ((fd = g_open(pathToNetSnmp6, O_RDONLY)) == -1) { + return NULL; + } + + myChannel = g_io_channel_unix_new(fd); + + myHashTable = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); + + /* + * Expected format: + * + * key1 value1 + * key2 value2 + * ... + * keyN valueN + */ + + while ((ioStatus = g_io_channel_read_line(myChannel, &myInputLine, NULL, + NULL, NULL)) == G_IO_STATUS_NORMAL) { + GMatchInfo *matchInfo = NULL; + + if (g_regex_match(myRegex, myInputLine, 0, &matchInfo)) { + gchar *myKey = NULL; + gchar *myVal = NULL; + guint64 *myIntVal = NULL; + + myKey = g_match_info_fetch(matchInfo, 1); + myVal = g_match_info_fetch(matchInfo, 2); + + /* + * By virtue of having matched the above regex, this conversion + * must hold. + */ + myIntVal = g_new(guint64, 1); + *myIntVal = g_ascii_strtoull(myVal, NULL, 10); + + /* + * The hash table will take ownership of myKey and myIntVal. We're + * still responsible for myVal. + */ + g_hash_table_insert(myHashTable, myKey, myIntVal); + g_free(myVal); + } else { + parseError = TRUE; + } + + g_match_info_free(matchInfo); + g_free(myInputLine); + myInputLine = NULL; + + if (parseError) { + break; + } + } + + if (ioStatus == G_IO_STATUS_ERROR || + g_hash_table_size(myHashTable) == 0 || + parseError) { + g_hash_table_destroy(myHashTable); + myHashTable = NULL; + } + + close(fd); + + g_free(myChannel); + + return myHashTable; +} + + +/* + ****************************************************************************** + * SlashProcNet_GetRoute -- */ /** + * + * @brief Reads @ref pathToNetRoute and returns a @c GPtrArray of + * struct rtentrys. + * + * Example usage: + * @code + * GPtrArray *rtArray; + * guint i; + * rtArray = SlashProcNet_GetRoute(); + * for (i = 0; i < rtArray->len; i++) { + * struct rtentry *myRoute = g_ptr_array_index(rtArray, i); + * // Do something with myRoute->rt_dst. + * } + * SlashProcNet_FreeRoute(rtArray); + * @endcode + * + * @note Caller is responsible for freeing the @c GPtrArray with + * SlashProcNet_FreeRoute. + * @note This routine creates persistent GLib GRegexs. + * + * @return On failure, NULL. On success, a valid @c GPtrArray. + * @todo Consider init/cleanup routines to not "leak" GRegexs. + * @todo Consider rewriting, integrating with libdnet. + * + ****************************************************************************** + */ + +GPtrArray * +SlashProcNet_GetRoute(void) +{ + GIOChannel *myChannel = NULL; + GIOStatus myIoStatus; + GPtrArray *myArray = NULL; + gchar *myLine = NULL; + int fd = -1; + + static GRegex *myFieldsRE = NULL; + static GRegex *myValuesRE = NULL; + + if (myFieldsRE == NULL) { + myFieldsRE = g_regex_new("^Iface\\s+Destination\\s+Gateway\\s+Flags\\s+" + "RefCnt\\s+Use\\s+Metric\\s+Mask\\s+MTU\\s+" + "Window\\s+IRTT\\s*$", 0, 0, NULL); + myValuesRE = g_regex_new("^(\\w+)\\s+([[:xdigit:]]{8})\\s+" + "([[:xdigit:]]{8})\\s+([[:xdigit:]]{4})\\s+" + "\\d+\\s+\\d+\\s+(\\d+)\\s+" + "([[:xdigit:]]{8})\\s+(\\d+)\\s+\\d+\\s+(\\d+)\\s*$", + 0, 0, NULL); + ASSERT(myFieldsRE); + ASSERT(myValuesRE); + } + + /* + * 1. Open pathToNetRoute, associate it with a GIOChannel. + */ + + if ((fd = g_open(pathToNetRoute, O_RDONLY)) == -1) { + Warning("%s: open(%s): %s\n", __func__, pathToNetRoute, + g_strerror(errno)); + return NULL; + } + + myChannel = g_io_channel_unix_new(fd); + + /* + * 2. Sanity check the header, making sure it matches what we expect. + * (It's -extremely- unlikely this will change, but we should check + * anyway.) + */ + + myIoStatus = g_io_channel_read_line(myChannel, &myLine, NULL, NULL, NULL); + if (myIoStatus != G_IO_STATUS_NORMAL || + g_regex_match(myFieldsRE, myLine, 0, NULL) == FALSE) { + goto out; + } + + g_free(myLine); + myLine = NULL; + + myArray = g_ptr_array_new(); + + /* + * 3. For each line... + */ + + while ((myIoStatus = g_io_channel_read_line(myChannel, &myLine, NULL, NULL, + NULL)) == G_IO_STATUS_NORMAL) { + GMatchInfo *myMatchInfo = NULL; + struct rtentry *myEntry = NULL; + struct sockaddr_in *sin = NULL; + Bool parseError = FALSE; + + /* + * 3a. Validate with regex. + */ + if (!g_regex_match(myValuesRE, myLine, 0, &myMatchInfo)) { + parseError = TRUE; + goto badIteration; + } + + /* + * 3b. Allocate new rtentry, add to array. This simplifies the cleanup + * code path. + */ + myEntry = g_new0(struct rtentry, 1); + g_ptr_array_add(myArray, myEntry); + + /* + * 3c. Copy contents to new struct rtentry. + */ + myEntry->rt_dev = g_match_info_fetch(myMatchInfo, 1); + + sin = (struct sockaddr_in *)&myEntry->rt_dst; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = MatchToGuint64(myMatchInfo, 2, 16); + + sin = (struct sockaddr_in *)&myEntry->rt_gateway; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = MatchToGuint64(myMatchInfo, 3, 16); + + sin = (struct sockaddr_in *)&myEntry->rt_genmask; + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = MatchToGuint64(myMatchInfo, 6, 16); + + myEntry->rt_flags = MatchToGuint64(myMatchInfo, 4, 16); + myEntry->rt_metric = MatchToGuint64(myMatchInfo, 5, 10); + myEntry->rt_mtu = MatchToGuint64(myMatchInfo, 7, 10); + myEntry->rt_irtt = MatchToGuint64(myMatchInfo, 8, 10); + +badIteration: + g_free(myLine); + myLine = NULL; + + g_match_info_free(myMatchInfo); + myMatchInfo = NULL; + + if (parseError) { + break; + } + } + + if (myArray && myIoStatus != G_IO_STATUS_EOF) { + SlashProcNet_FreeRoute(myArray); + myArray = NULL; + } + +out: + g_free(myLine); + g_free(myChannel); + + close(fd); + + return myArray; +} + + +/* + ****************************************************************************** + * SlashProcNet_FreeRoute -- */ /** + * + * @brief Frees memory associated with a GPtrArray allocated by + * SlashProcNet_GetRoute. + * + * @param[in] routeArray Array to free. + * + ****************************************************************************** + */ + +void +SlashProcNet_FreeRoute(GPtrArray *routeArray) +{ + int i; + + if (routeArray == NULL) { + return; + } + + for (i = 0; i < routeArray->len; i++) { + struct rtentry *myEntry = g_ptr_array_index(routeArray, i); + ASSERT(myEntry->rt_dev); + g_free(myEntry->rt_dev); + g_free(myEntry); + } + + g_ptr_array_free(routeArray, TRUE); +} + + +/* + ****************************************************************************** + * SlashProcNet_GetRoute6 -- */ /** + * + * @brief Reads @ref pathToNetRoute6 and returns a @c GPtrArray of + * struct in6_rtmsgs. + * + * Example usage: + * @code + * GPtrArray *rtArray; + * guint i; + * rtArray = SlashProcNet_GetRoute6(); + * for (i = 0; i < rtArray->len; i++) { + * struct in6_rtmsg *myRoute = g_ptr_array_index(rtArray, i); + * // Do something with myRoute->rtmsg_dst. + * } + * SlashProcNet_FreeRoute6(rtArray, TRUE); + * @endcode + * + * @note Caller is responsible for freeing the @c GPtrArray with + * SlashProcNet_FreeRoute6. + * @note This routine creates persistent GLib GRegexs. + * + * @return On failure, NULL. On success, a valid @c GPtrArray. + * @todo Consider init/cleanup routines to not "leak" GRegexs. + * @todo Consider rewriting, integrating with libdnet. + * + ****************************************************************************** + */ + +GPtrArray * +SlashProcNet_GetRoute6(void) +{ + GIOChannel *myChannel = NULL; + GIOStatus myIoStatus; + GPtrArray *myArray = NULL; + gchar *myLine = NULL; + Bool parseError = FALSE; + int fd = -1; + + static GRegex *myValuesRE = NULL; + + if (myValuesRE == NULL) { + myValuesRE = g_regex_new("^([[:xdigit:]]{32}) ([[:xdigit:]]{2}) " + "([[:xdigit:]]{32}) ([[:xdigit:]]{2}) " + "([[:xdigit:]]{32}) ([[:xdigit:]]{8}) " + "[[:xdigit:]]{8} [[:xdigit:]]{8} " + "([[:xdigit:]]{8})\\s+(\\w+)\\s*$", 0, 0, + NULL); + ASSERT(myValuesRE); + } + + /* + * 1. Open pathToNetRoute6, associate it with a GIOChannel. + */ + + if ((fd = g_open(pathToNetRoute6, O_RDONLY)) == -1) { + Warning("%s: open(%s): %s\n", __func__, pathToNetRoute, + g_strerror(errno)); + return NULL; + } + + myChannel = g_io_channel_unix_new(fd); + + myArray = g_ptr_array_new(); + + while ((myIoStatus = g_io_channel_read_line(myChannel, &myLine, NULL, NULL, + NULL)) == G_IO_STATUS_NORMAL) { + struct in6_rtmsg *myEntry = NULL; + GMatchInfo *myMatchInfo = NULL; + + if (!g_regex_match(myValuesRE, myLine, 0, &myMatchInfo)) { + parseError = TRUE; + goto badIteration; + } + + myEntry = g_new0(struct in6_rtmsg, 1); + g_ptr_array_add(myArray, myEntry); + + MATCHEXPR(myMatchInfo, 1, Ip6StringToIn6Addr(MATCH, &myEntry->rtmsg_dst)); + MATCHEXPR(myMatchInfo, 3, Ip6StringToIn6Addr(MATCH, &myEntry->rtmsg_src)); + MATCHEXPR(myMatchInfo, 5, Ip6StringToIn6Addr(MATCH, &myEntry->rtmsg_gateway)); + + myEntry->rtmsg_dst_len = MatchToGuint64(myMatchInfo, 2, 16); + myEntry->rtmsg_src_len = MatchToGuint64(myMatchInfo, 4, 16); + myEntry->rtmsg_metric = MatchToGuint64(myMatchInfo, 6, 16); + myEntry->rtmsg_flags = MatchToGuint64(myMatchInfo, 7, 16); + + MATCHEXPR(myMatchInfo, 8, myEntry->rtmsg_ifindex = NetUtil_GetIfIndex(MATCH)); + +badIteration: + g_free(myLine); + myLine = NULL; + + g_match_info_free(myMatchInfo); + myMatchInfo = NULL; + + if (parseError) { + break; + } + } + + if (myArray && myIoStatus != G_IO_STATUS_EOF) { + g_ptr_array_free(myArray, TRUE); + myArray = NULL; + } + + g_free(myLine); + myLine = NULL; + g_free(myChannel); + myChannel = NULL; + + return myArray; +} + + +/* + ****************************************************************************** + * SlashProcNet_FreeRoute6 -- */ /** + * + * @brief Frees memory associated with a GPtrArray allocated by + * SlashProcNet_GetRoute6. + * + * @param[in] routeArray Array to free. + * + ****************************************************************************** + */ + +void +SlashProcNet_FreeRoute6(GPtrArray *routeArray) +{ + int i; + + if (routeArray == NULL) { + return; + } + + for (i = 0; i < routeArray->len; i++) { + struct rtentry *myEntry = g_ptr_array_index(routeArray, i); + g_free(myEntry); + } + + g_ptr_array_free(routeArray, TRUE); +} + + +/* + * Private functions. + */ + + +/* + ****************************************************************************** + * Ip6StringToIn6Addr -- */ /** + * + * @brief Parses a @c /proc/net/ipv6_route hexadecimal IPv6 address and + * records it in a struct in6_addr. + * + * @param[in] ip6String Source string. + * @param[out] in6_addr Output struct. + * + ****************************************************************************** + */ + +static void +Ip6StringToIn6Addr(const char *ip6String, + struct in6_addr *in6_addr) +{ + unsigned int i; + + ASSERT(strlen(ip6String) == 32); + + for (i = 0; i < 16; i++) { + int nmatched; + nmatched = sscanf(&ip6String[2 * i], "%2hhx", &in6_addr->s6_addr[i]); + ASSERT(nmatched == 1); + } +} + + +/* + ****************************************************************************** + * MatchToGuint64 -- */ /** + * + * @brief Wrapper around @c g_ascii_strtoull and @c g_match_info_fetch. + * + * @param[in] matchInfo Source regular expression match context. + * @param[in] matchIndex Match number to fetch. + * @param[in] base Base represented by matched string. + * (See @c g_ascii_strtoull docs.) + * + ****************************************************************************** + */ + +static guint64 +MatchToGuint64(const GMatchInfo *matchInfo, + const gint matchIndex, + gint base) +{ + guint64 retval; + MATCHEXPR(matchInfo, matchIndex, retval = g_ascii_strtoull(MATCH, NULL, base)); + return retval; +} diff --git a/open-vm-tools/lib/slashProc/slashProcNetInt.h b/open-vm-tools/lib/slashProc/slashProcNetInt.h new file mode 100644 index 000000000..eaeada1cb --- /dev/null +++ b/open-vm-tools/lib/slashProc/slashProcNetInt.h @@ -0,0 +1,39 @@ +/********************************************************* + * Copyright (C) 2009 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. + * + *********************************************************/ + +/** + * @file netInt.h + * + * SlashProcNet internal bits. + */ + +#ifndef _SLASHPROCNETINT_H_ +#define _SLASHPROCNETINT_H_ + +#define INCLUDE_ALLOW_USERLEVEL +#include "includeCheck.h" + +#ifdef VMX86_DEVEL +EXTERN void SlashProcNetSetPathSnmp(const char *newPathToNetSnmp); +EXTERN void SlashProcNetSetPathSnmp6(const char *newPathToNetSnmp6); +EXTERN void SlashProcNetSetPathRoute(const char *newPathToNetRoute); +EXTERN void SlashProcNetSetPathRoute6(const char *newPathToNetRoute6); +#endif // ifdef VMX86_DEVEL + +#endif // ifndef _SLASHPROCNETINT_H_ + diff --git a/open-vm-tools/lib/unity/unityPlatformX11Window.c b/open-vm-tools/lib/unity/unityPlatformX11Window.c index 0297a5aa6..f0fa844cf 100644 --- a/open-vm-tools/lib/unity/unityPlatformX11Window.c +++ b/open-vm-tools/lib/unity/unityPlatformX11Window.c @@ -2227,7 +2227,7 @@ UnityPlatformGetWindowContents(UnityPlatform *up, // IN vmimage.bytesPerLine = ximage->bytes_per_line; vmimage.data = ximage->data; - if (ImageUtil_ConstructPNGBuffer(&vmimage, imageData)) { + if (ImageUtil_ConstructPNGBuffer(&vmimage, NULL, imageData)) { result = TRUE; } diff --git a/open-vm-tools/lib/unityWindowTracker/unityWindowTracker.c b/open-vm-tools/lib/unityWindowTracker/unityWindowTracker.c index 1a85c35a8..60c2a72fa 100644 --- a/open-vm-tools/lib/unityWindowTracker/unityWindowTracker.c +++ b/open-vm-tools/lib/unityWindowTracker/unityWindowTracker.c @@ -887,6 +887,12 @@ UnityWindowTracker_SendUpdate(UnityWindowTracker *tracker, // IN case UNITY_UPDATE_CHANGE_ZORDER: UnityWindowTracker_SetZOrder(tracker, update->u.zorder.ids, update->u.zorder.count); + /* + * This function is only every called from the host. Thus, if we get + * a zorder changed event from the guest it's safe to blindly trust it + * mark the zorder as changed. See bug 409742 for more info. + */ + tracker->zorderChanged = TRUE; break; case UNITY_UPDATE_CHANGE_WINDOW_STATE: diff --git a/open-vm-tools/lib/user/hostinfo.c b/open-vm-tools/lib/user/hostinfo.c index f7cfb286e..7167b0754 100644 --- a/open-vm-tools/lib/user/hostinfo.c +++ b/open-vm-tools/lib/user/hostinfo.c @@ -28,6 +28,7 @@ #include "cpuid_info.h" #include "hostinfo.h" +#include "util.h" #define LOGLEVEL_MODULE hostinfo #include "loglevel_user.h" @@ -253,6 +254,41 @@ Hostinfo_GetCpuid(HostinfoCpuIdInfo *info) // OUT } +/* + *---------------------------------------------------------------------- + * + * Hostinfo_HypervisorCPUIDSig -- + * + * Get the hypervisor signature string from CPUID. + * + * Results: + * Unqualified 16 byte nul-terminated hypervisor string + * String may contain garbage and caller must free + * + * Side effects: + * None + * + *---------------------------------------------------------------------- + */ + +char * +Hostinfo_HypervisorCPUIDSig(void) +{ + CPUIDRegs regs; + uint32 *name; + + name = Util_SafeMalloc(4 * sizeof *name); + + __GET_CPUID(0x40000000, ®s); + name[0] = regs.ebx; + name[1] = regs.ecx; + name[2] = regs.edx; + name[3] = 0; + + return (char *)name; +} + + /* *---------------------------------------------------------------------- * @@ -260,8 +296,9 @@ Hostinfo_GetCpuid(HostinfoCpuIdInfo *info) // OUT * * Check for Xen. * - * Official way is to check CPUID function 0x4000 0000, which - * returns a hypervisor string. See PR156185, + * Official way is to call Hostinfo_HypervisorCPUIDSig(), which + * returns a hypervisor string. This is a secondary check + * that guards against a backdoor failure. See PR156185, * http://xenbits.xensource.com/xen-unstable.hg?file/6a383beedf83/tools/misc/xen-detect.c * (Canonical way is /proc/xen, but CPUID is better). * @@ -283,26 +320,12 @@ Hostinfo_GetCpuid(HostinfoCpuIdInfo *info) // OUT Bool Hostinfo_TouchXen(void) { +#ifdef linux #define XEN_CPUID 0x40000000 #define XEN_STRING "XenVMMXenVMM" CPUIDRegs regs; uint32 name[4]; - /* - * HVM mode: simple cpuid instr - * Xen hypervisor traps CPUID and adds information leaf(s) - * at CPUID leaf XEN_CPUID and higher. - */ - __GET_CPUID(XEN_CPUID, ®s); - name[0] = regs.ebx; - name[1] = regs.ecx; - name[2] = regs.edx; - name[3] = 0; - if (0 == strcmp(XEN_STRING, (const char*)name)) { - return TRUE; - } - -#ifdef linux /* * PV mode: ud2a "xen" cpuid (faults on native hardware). * (Only Linux can run PV, so skip others here). diff --git a/open-vm-tools/lib/user/util.c b/open-vm-tools/lib/user/util.c index 42d9d9753..328703e08 100644 --- a/open-vm-tools/lib/user/util.c +++ b/open-vm-tools/lib/user/util.c @@ -177,7 +177,7 @@ Util_Init(void) */ uint32 -Util_Checksum32(uint32 *buf, int len) +Util_Checksum32(const uint32 *buf, int len) { uint32 checksum = 0; int i; @@ -200,7 +200,7 @@ Util_Checksum32(uint32 *buf, int len) */ uint32 -Util_Checksum(uint8 *buf, int len) +Util_Checksum(const uint8 *buf, int len) { uint32 checksum; int remainder, shift; @@ -655,20 +655,34 @@ Util_BacktraceToBuffer(uintptr_t *basePtr, Bool Util_Data2Buffer(char *buf, // OUT size_t bufSize, // IN - const void* data0, // IN + const void *data0, // IN size_t dataSize) // IN { - char* cp = buf; - const uint8* data = (const uint8*) data0; - size_t n = MIN(dataSize, ((bufSize-1) / 3)); - - while (n > 0) { - Str_Sprintf(cp, 4, " %02X", *data); - cp += 3; - data++, n--; + size_t n; + + /* At least 1 byte (for NUL) must be available. */ + if (!bufSize) { + return FALSE; + } + + bufSize = bufSize / 3; + n = MIN(dataSize, bufSize); + if (n != 0) { + const uint8 *data = data0; + + while (n > 0) { + static const char digits[] = "0123456789ABCDEF"; + + *buf++ = digits[*data >> 4]; + *buf++ = digits[*data & 0xF]; + *buf++ = ' '; + data++; + n--; + } + buf--; } - *cp = '\0'; - return (dataSize <= bufSize); + *buf = 0; + return dataSize <= bufSize; } diff --git a/open-vm-tools/lib/user/utilPosix.c b/open-vm-tools/lib/user/utilPosix.c index 828fc7012..a87039331 100644 --- a/open-vm-tools/lib/user/utilPosix.c +++ b/open-vm-tools/lib/user/utilPosix.c @@ -125,14 +125,18 @@ Util_BumpNoFds(uint32 *cur, // OUT int err; /* - * Check for minimum file descriptor limit. The number 2048 is + * Check for minimum file descriptor limit. The number is * somewhat arbitrary. Trying to do multiple snapshots of a split * disk can rapidly consume descriptors however, so we ought to * have a large number. This is only pushing back the problem of * course. Ideally we'd have a fully scalable solution. */ +#if __APPLE__ + static const rlim_t fdsDesired = 8192; +#else static const rlim_t fdsDesired = 2048; +#endif err = getrlimit(RLIMIT_NOFILE, &lim); ASSERT_NOT_IMPLEMENTED(err >= 0); diff --git a/open-vm-tools/lib/vixTools/vixTools.c b/open-vm-tools/lib/vixTools/vixTools.c index 3c3cfcedd..174ab5915 100644 --- a/open-vm-tools/lib/vixTools/vixTools.c +++ b/open-vm-tools/lib/vixTools/vixTools.c @@ -95,6 +95,7 @@ #include "registryWin32.h" #include "win32u.h" #endif /* _WIN32 */ +#include "hgfsHelper.h" #ifdef linux #include "mntinfo.h" @@ -227,6 +228,8 @@ static VixError VixToolsSetGuestNetworkingConfig(VixCommandRequestHeader *reques static VixError VixTools_Base64EncodeBuffer(char **resultValuePtr, size_t *resultValLengthPtr); +static VixError VixToolsSetSharedFoldersProperties(VixPropertyListImpl *propList); + #if defined(_WIN32) static HRESULT VixToolsEnableDHCPOnPrimary(void); @@ -953,6 +956,9 @@ VixTools_GetToolsPropertiesImpl(GuestApp_Dict **confDictRef, // IN goto abort; } + /* Retrieve the share folders UNC root path. */ + err = VixToolsSetSharedFoldersProperties(&propList); + /* * Serialize the property list to buffer then encode it. * This is the string we return to the VMX process. @@ -981,6 +987,9 @@ abort: VixPropertyList_Initialize(&propList); + /* Retrieve the share folders UNC root path. */ + err = VixToolsSetSharedFoldersProperties(&propList); + /* * Serialize the property list to buffer then encode it. * This is the string we return to the VMX process. @@ -1005,6 +1014,52 @@ abort: } // VixTools_GetToolsPropertiesImpl +/* + *----------------------------------------------------------------------------- + * + * VixToolsSetSharedFoldersProperties -- + * + * Set information about the shared folders feature. + * + * Return value: + * VixError + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +static VixError +VixToolsSetSharedFoldersProperties(VixPropertyListImpl *propList) // IN +{ + VixError err = VIX_OK; + + /* Retrieve the share folders UNC root path. */ + Unicode hgfsRootPath = NULL; + + if (!HgfsHlpr_QuerySharesDefaultRootPath(&hgfsRootPath)) { + /* Exit ok as we have nothing to set from shared folders. */ + goto exit; + } + + ASSERT(hgfsRootPath != NULL); + + err = VixPropertyList_SetString(propList, + VIX_PROPERTY_GUEST_SHAREDFOLDERS_SHARES_PATH, + UTF8(hgfsRootPath)); + if (VIX_OK != err) { + goto exit; + } + +exit: + if (hgfsRootPath != NULL) { + HgfsHlpr_FreeSharesRootPath(hgfsRootPath); + } + return err; +} + + #if 0 /* *----------------------------------------------------------------------------- @@ -3653,23 +3708,116 @@ VixToolsDoesUsernameMatchCurrentUser(const char *username) // IN #ifdef _WIN32 char *currentUser = NULL; DWORD currentUserSize = 0; - + DWORD retVal = 0; + HANDLE processToken = INVALID_HANDLE_VALUE; + PTOKEN_USER processTokenInfo = NULL; + DWORD processTokenInfoSize = 0; + Unicode sidUserName = NULL; + DWORD sidUserNameSize = 0; + Unicode sidDomainName = NULL; + DWORD sidDomainNameSize = 0; + SID_NAME_USE sidNameUse; + /* - * For Windows, get the name of the owner of this process, then - * compare it to the provided username. + * Check to see if the user provided a '\' formatted username */ - if (!Win32U_GetUserName(currentUser, ¤tUserSize)) { + if (NULL != Str_Strchr(username, '\\')) { + /* + * A '\' formatted username was provided. + * We must retrieve the domain as well as the username to verify + * the current vixtools user matches the username provided + */ + retVal = OpenProcessToken(GetCurrentProcess(), + TOKEN_READ, + &processToken); + + if (!retVal || !processToken) { + Warning("unable to open process token: windows error code %d\n", + GetLastError()); + err = FoundryToolsDaemon_TranslateSystemErr(); + + goto abort; + } + + // Determine necessary buffer size + GetTokenInformation(processToken, + TokenUser, + NULL, + 0, + &processTokenInfoSize); + if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) { + Warning("unable to get token info: windows error code %d\n", + GetLastError()); err = FoundryToolsDaemon_TranslateSystemErr(); goto abort; } - currentUser = Util_SafeMalloc(currentUserSize); + processTokenInfo = Util_SafeMalloc(processTokenInfoSize); - if (!Win32U_GetUserName(currentUser, ¤tUserSize)) { + if (!GetTokenInformation(processToken, + TokenUser, + processTokenInfo, + processTokenInfoSize, + &processTokenInfoSize)) { + Warning("unable to get token info: windows error code %d\n", + GetLastError()); + err = FoundryToolsDaemon_TranslateSystemErr(); + goto abort; + } + + // Retrieve user name and domain name based on user's SID. + Win32U_LookupAccountSid(NULL, + processTokenInfo->User.Sid, + NULL, + &sidUserNameSize, + NULL, + &sidDomainNameSize, + &sidNameUse); + + if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) { + Warning("unable to lookup account sid: windows error code %d\n", + GetLastError()); err = FoundryToolsDaemon_TranslateSystemErr(); goto abort; } + + sidUserName = Util_SafeMalloc(sidUserNameSize); + sidDomainName = Util_SafeMalloc(sidDomainNameSize); + + if (!Win32U_LookupAccountSid(NULL, + processTokenInfo->User.Sid, + sidUserName, + &sidUserNameSize, + sidDomainName, + &sidDomainNameSize, + &sidNameUse)) { + Warning("unable to lookup account sid: windows error code %d\n", + GetLastError()); + err = FoundryToolsDaemon_TranslateSystemErr(); + goto abort; + } + + // Populate currentUser with Domain + '\' + Username + currentUser = Str_SafeAsprintf(NULL, "%s\\%s", sidDomainName, sidUserName); + } else { + /* + * For Windows, get the name of the owner of this process, then + * compare it to the provided username. + */ + if (!Win32U_GetUserName(currentUser, ¤tUserSize)) { + if (ERROR_INSUFFICIENT_BUFFER != GetLastError()) { + err = FoundryToolsDaemon_TranslateSystemErr(); + goto abort; + } + + currentUser = Util_SafeMalloc(currentUserSize); + + if (!Win32U_GetUserName(currentUser, ¤tUserSize)) { + err = FoundryToolsDaemon_TranslateSystemErr(); + goto abort; + } + } } if (0 != Unicode_CompareIgnoreCase(username, currentUser)) { @@ -3680,6 +3828,10 @@ VixToolsDoesUsernameMatchCurrentUser(const char *username) // IN err = VIX_OK; abort: + free(sidDomainName); + free(sidUserName); + free(processTokenInfo); + CloseHandle(processToken); free(currentUser); #else /* Below is the POSIX case. */ diff --git a/open-vm-tools/lib/wiper/Makefile.am b/open-vm-tools/lib/wiper/Makefile.am index a17f35f07..762e2eb7c 100644 --- a/open-vm-tools/lib/wiper/Makefile.am +++ b/open-vm-tools/lib/wiper/Makefile.am @@ -18,4 +18,5 @@ noinst_LTLIBRARIES = libWiper.la libWiper_la_SOURCES = +libWiper_la_SOURCES += wiperCommon.c libWiper_la_SOURCES += wiperPosix.c diff --git a/open-vm-tools/lib/wiper/wiperCommon.c b/open-vm-tools/lib/wiper/wiperCommon.c new file mode 100644 index 000000000..90b0ea8ed --- /dev/null +++ b/open-vm-tools/lib/wiper/wiperCommon.c @@ -0,0 +1,122 @@ +/********************************************************* + * Copyright (C) 2009 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. + * + *********************************************************/ + +/* + * wiperCommon.c -- + * + * OS-agnostic parts of the library for wiping a virtual disk. + * + */ + +#include +#include +#include "dbllnklst.h" +#include "wiper.h" +#include "util.h" + +/* + *----------------------------------------------------------------------------- + * + * WiperSinglePartition_Allocate -- + * + * Allocates and initialized empty WiperPartition structure. + * + * Results: + * NULL if there is no memory, otherwise a pointer to newly allocated + * WiperPartition structure. + * + * Side Effects: + * Allocates memory. + * + *----------------------------------------------------------------------------- + */ + +WiperPartition * +WiperSinglePartition_Allocate(void) +{ + WiperPartition *p = (WiperPartition *) malloc(sizeof *p); + + if (p != NULL) { + memset(p->mountPoint, 0, sizeof p->mountPoint); + p->type = PARTITION_UNSUPPORTED; + p->comment = NULL; + DblLnkLst_Init(&p->link); + } + + return p; +} + + +/* + *----------------------------------------------------------------------------- + * + * WiperSinglePartition_Close -- + * + * Destroy the information returned by a previous call to + * WiperSinglePartition_Allocate(). The partition should be removed + * from all lists prior to calling WiperSinglePartition_Close(). + * + * Results: + * None. + * + * Side Effects: + * Frees memory occupied by the element. + * + *----------------------------------------------------------------------------- + */ + +void +WiperSinglePartition_Close(WiperPartition *p) // IN +{ + if (p) { + free((char *)p->comment); /* Casting away constness */ + free(p); + } +} + + +/* + *--------------------------------------------------------------------------- + * + * WiperPartition_Close -- + * + * Destroy the information collected by previous call to + * WiperPartition_Open(). + * + * Results: + * None + * + * Side Effects: + * Frees memory occupied by elements of the list. + * + *--------------------------------------------------------------------------- + */ + +void +WiperPartition_Close(WiperPartition_List *pl) // IN/OUT +{ + DblLnkLst_Links *curr, *next; + + DblLnkLst_ForEachSafe(curr, next, &pl->link) { + WiperPartition *part = DblLnkLst_Container(curr, WiperPartition, link); + + DblLnkLst_Unlink1(curr); + WiperSinglePartition_Close(part); + } +} + diff --git a/open-vm-tools/lib/wiper/wiperPosix.c b/open-vm-tools/lib/wiper/wiperPosix.c index 32393255f..add12c9d1 100644 --- a/open-vm-tools/lib/wiper/wiperPosix.c +++ b/open-vm-tools/lib/wiper/wiperPosix.c @@ -50,6 +50,7 @@ #include "vmstdio.h" #include "mntinfo.h" #include "posix.h" +#include "util.h" /* Number of bytes per disk sector */ @@ -370,6 +371,9 @@ WiperPartitionFilter(WiperPartition *item, // IN/OUT MNTINFO *mnt) // IN { struct stat s; + const char *comment = NULL; + + item->type = PARTITION_UNSUPPORTED; /* * Let's ignore remote filesystems before we do a stat(2) on the actual @@ -378,137 +382,76 @@ WiperPartitionFilter(WiperPartition *item, // IN/OUT */ if (strcmp(MNTINFO_FSTYPE(mnt), "autofs") == 0) { /* XXX Should we look at autofs' config files? --hpreg */ - item->comment = "Not implemented. Contact VMware"; - return; - } + comment = "Not implemented. Contact VMware"; - if (strcmp(MNTINFO_FSTYPE(mnt), "vmhgfs") == 0) { - item->comment = "Remote partition"; - return; - } + } else if (strcmp(MNTINFO_FSTYPE(mnt), "vmhgfs") == 0) { + comment = "Remote partition"; - if (strcmp(MNTINFO_FSTYPE(mnt), "nfs") == 0) { - item->comment = "Remote filesystem"; - return; - } + } if (strcmp(MNTINFO_FSTYPE(mnt), "nfs") == 0) { + comment = "Remote filesystem"; - if (strcmp(MNTINFO_FSTYPE(mnt), "smbfs") == 0) { - item->comment = "Remote filesystem"; - return; - } + } if (strcmp(MNTINFO_FSTYPE(mnt), "smbfs") == 0) { + comment = "Remote filesystem"; - if (strcmp(MNTINFO_FSTYPE(mnt), "swap") == 0) { - item->comment = "Swap partition"; - return; - } + } if (strcmp(MNTINFO_FSTYPE(mnt), "swap") == 0) { + comment = "Swap partition"; - if (strcmp(MNTINFO_FSTYPE(mnt), PROCFS) == 0) { - item->comment = "Proc partition"; - return; - } + } if (strcmp(MNTINFO_FSTYPE(mnt), PROCFS) == 0) { + comment = "Proc partition"; - if (strcmp(MNTINFO_FSTYPE(mnt), "devpts") == 0) { - item->comment = "Devpts partition"; - return; - } + } if (strcmp(MNTINFO_FSTYPE(mnt), "devpts") == 0) { + comment = "Devpts partition"; - if (Posix_Stat(MNTINFO_NAME(mnt), &s) < 0) { - item->comment = "Unknown device"; - return; - } + } if (Posix_Stat(MNTINFO_NAME(mnt), &s) < 0) { + comment = "Unknown device"; #if defined(sun) || defined(__linux__) - if (! S_ISBLK(s.st_mode)) { - item->comment = "Not a block device"; - return; - } + } else if (! S_ISBLK(s.st_mode)) { + comment = "Not a block device"; #endif - if (!WiperIsDiskDevice(mnt, &s)) { - item->comment = "Not a disk device"; - return; - } + } else if (!WiperIsDiskDevice(mnt, &s)) { + comment = "Not a disk device"; - if (MNTINFO_MNT_IS_RO(mnt)) { - item->comment = "Not writable"; - return; - } + } if (MNTINFO_MNT_IS_RO(mnt)) { + comment = "Not writable"; - if (strcmp(MNTINFO_FSTYPE(mnt), "ext2") == 0) { - item->comment = ""; + } if (strcmp(MNTINFO_FSTYPE(mnt), "ext2") == 0) { item->type = PARTITION_EXT2; - return; - } - if (strcmp(MNTINFO_FSTYPE(mnt), "ext3") == 0) { - item->comment = ""; + } if (strcmp(MNTINFO_FSTYPE(mnt), "ext3") == 0) { item->type = PARTITION_EXT3; - return; - } - if (strcmp(MNTINFO_FSTYPE(mnt), "reiserfs") == 0) { - item->comment = ""; + } if (strcmp(MNTINFO_FSTYPE(mnt), "reiserfs") == 0) { item->type = PARTITION_REISERFS; - return; - } - if (strcmp(MNTINFO_FSTYPE(mnt), "ntfs") == 0) { - item->comment = ""; + } if (strcmp(MNTINFO_FSTYPE(mnt), "ntfs") == 0) { item->type = PARTITION_NTFS; - return; - } - if (strcmp(MNTINFO_FSTYPE(mnt), "vfat") == 0) { - item->comment = ""; + } if (strcmp(MNTINFO_FSTYPE(mnt), "vfat") == 0) { item->type = PARTITION_FAT; - return; - } - if (strcmp(MNTINFO_FSTYPE(mnt), "ufs") == 0) { - item->comment = ""; + } if (strcmp(MNTINFO_FSTYPE(mnt), "ufs") == 0) { item->type = PARTITION_UFS; - return; - } - if (strcmp(MNTINFO_FSTYPE(mnt), "pcfs") == 0) { - item->comment = ""; + } if (strcmp(MNTINFO_FSTYPE(mnt), "pcfs") == 0) { item->type = PARTITION_PCFS; - return; - } - item->comment = "Unknown filesystem. Contact VMware"; - return; -} - - -/* - *----------------------------------------------------------------------------- - * - * SingleWiperPartition_Close -- - * - * Destroy the information returned by a previous call to - * SingleWiperPartition_Open(). - * - * Results: - * None - * - * Side Effects: - * None - * - *----------------------------------------------------------------------------- - */ + } else { + comment = "Unknown filesystem. Contact VMware"; + } -void -SingleWiperPartition_Close(WiperPartition *p) // IN -{ - free(p); + if (item->type == PARTITION_UNSUPPORTED) { + ASSERT(comment); + item->comment = Util_SafeStrdup(comment); + } } /* *----------------------------------------------------------------------------- * - * SingleWiperPartition_Open -- + * WiperSinglePartition_Open -- * * Return information about the input 'mountPoint' partition. * @@ -523,26 +466,20 @@ SingleWiperPartition_Close(WiperPartition *p) // IN */ WiperPartition * -SingleWiperPartition_Open(const char *mountPoint) // IN +WiperSinglePartition_Open(const char *mountPoint) // IN { char *mntpt = NULL; MNTHANDLE fp; int len = 0; DECLARE_MNTINFO(mnt); - WiperPartition *p; + WiperPartition *p = NULL; ASSERT(initDone); - fp = NULL; - p = (WiperPartition *) malloc(sizeof *p); - if (p == NULL) { - Log("Not enough memory while opening a partition.\n"); - goto error; - } fp = OPEN_MNTFILE("r"); if (fp == NULL) { Log("Could not open %s\n", MNTFILE); - goto error; + return NULL; } mntpt = Util_SafeStrdup(mountPoint); @@ -560,33 +497,30 @@ SingleWiperPartition_Open(const char *mountPoint) // IN len = strlen(mntpt); while (GETNEXT_MNTINFO(fp, mnt)) { if (strncmp(MNTINFO_MNTPT(mnt), mntpt, len) == 0) { - if (Str_Snprintf(p->mountPoint, NATIVE_MAX_PATH, - "%s", MNTINFO_MNTPT(mnt)) == -1) { + + p = WiperSinglePartition_Allocate(); + if (p == NULL) { + Log("Not enough memory while opening a partition.\n"); + } else if (Str_Snprintf(p->mountPoint, NATIVE_MAX_PATH, + "%s", MNTINFO_MNTPT(mnt)) == -1) { Log("NATIVE_MAX_PATH is too small.\n"); - goto error; + WiperSinglePartition_Close(p); + p = NULL; + } else { + WiperCollectDiskMajors(); + WiperPartitionFilter(p, mnt); } - WiperCollectDiskMajors(); - WiperPartitionFilter(p, mnt); - (void) CLOSE_MNTFILE(fp); - - fp = NULL; - - free(mntpt); - return p; + goto out; } } Log("Could not find a mount point for %s in %s\n", mntpt, MNTFILE); - error: - SingleWiperPartition_Close(p); - if (fp != NULL) { - (void) CLOSE_MNTFILE(fp); - fp = NULL; - } + out: free(mntpt); - return NULL; + (void) CLOSE_MNTFILE(fp); + return p; } /* @@ -661,104 +595,55 @@ WiperSinglePartition_GetSpace(const WiperPartition *p, // IN *----------------------------------------------------------------------------- */ -WiperPartition_List * -WiperPartition_Open(void) +Bool +WiperPartition_Open(WiperPartition_List *pl) { - WiperPartition_List *pl; MNTHANDLE fp; DECLARE_MNTINFO(mnt); + Bool rc = TRUE; ASSERT(initDone); - fp = NULL; - pl = (WiperPartition_List *)malloc(sizeof *pl); - if (pl == NULL) { - Log("Not enough memory while opening a partition.\n"); - goto error; - } - - pl->partitions = NULL; - pl->size = 0; + DblLnkLst_Init(&pl->link); /* Basically call functions to parse /etc/mtab ... */ fp = OPEN_MNTFILE("r"); if (fp == NULL) { Log("Unable to open mount file.\n"); - goto error; + return FALSE; } WiperCollectDiskMajors(); while (GETNEXT_MNTINFO(fp, mnt)) { - WiperPartition item; - - if (Str_Snprintf(item.mountPoint, NATIVE_MAX_PATH, "%s", - MNTINFO_MNTPT(mnt)) == -1) { - Log("NATIVE_MAX_PATH is too small.\n"); - goto error; - } - - WiperPartitionFilter(&item, mnt); + WiperPartition *part = WiperSinglePartition_Allocate(); - /* Add the partition to the list */ - pl->partitions = (WiperPartition *)realloc(pl->partitions, - (pl->size + 1) * - sizeof *pl->partitions); - if (pl->partitions == NULL) { + if (part == NULL) { Log("Not enough memory while opening a partition.\n"); - goto error; + rc = FALSE; + break; } - pl->partitions[pl->size] = item; - pl->size++; - } - - (void) CLOSE_MNTFILE(fp); - fp = NULL; - - return pl; + if (Str_Snprintf(part->mountPoint, NATIVE_MAX_PATH, "%s", + MNTINFO_MNTPT(mnt)) == -1) { + Log("NATIVE_MAX_PATH is too small.\n"); + WiperSinglePartition_Close(part); + rc = FALSE; + break; + } -error: - WiperPartition_Close(pl); - pl = NULL; - if (fp != NULL) { - (void) CLOSE_MNTFILE(fp); - fp = NULL; + WiperPartitionFilter(part, mnt); + DblLnkLst_LinkLast(&pl->link, &part->link); } - return NULL; -} + if (!rc) + WiperPartition_Close(pl); -/* - *----------------------------------------------------------------------------- - * - * WiperPartition_Close -- - * - * Destroy the information returned by a previous call to - * WiperPartition_Open() - * - * Results: - * None - * - * Side Effects: - * None - * - *----------------------------------------------------------------------------- - */ - -void -WiperPartition_Close(WiperPartition_List *pl) // IN/OUT -{ - if (pl != NULL) { - free(pl->partitions); - pl->partitions = NULL; - free(pl); - } + (void) CLOSE_MNTFILE(fp); + return rc; } - - /* *----------------------------------------------------------------------------- * diff --git a/open-vm-tools/libvmtools/Makefile.am b/open-vm-tools/libvmtools/Makefile.am index c3d5c7334..7ad86a6a2 100644 --- a/open-vm-tools/libvmtools/Makefile.am +++ b/open-vm-tools/libvmtools/Makefile.am @@ -50,6 +50,10 @@ libvmtools_la_LIBADD += @LIBVMTOOLS_LIBADD@ libvmtools_la_LIBADD += @GLIB2_LIBS@ libvmtools_la_LIBADD += @ICU_LIBS@ +if LINUX +libvmtools_la_LIBADD += ../lib/slashProc/libSlashProc.la +endif + libvmtools_la_SOURCES = libvmtools_la_SOURCES += signalSource.c libvmtools_la_SOURCES += vmtools.c diff --git a/open-vm-tools/libvmtools/signalSource.c b/open-vm-tools/libvmtools/signalSource.c index b5f20b121..a35b1dcab 100644 --- a/open-vm-tools/libvmtools/signalSource.c +++ b/open-vm-tools/libvmtools/signalSource.c @@ -27,6 +27,7 @@ * used for reliable event delivery. */ +#include "vm_assert.h" #include "vmtools.h" #include #include @@ -82,7 +83,7 @@ SignalSourceReadSigInfo(void) return; } else { /* XXX: Maybe we should handle this in some other way? */ - g_assert(nbytes == sizeof info); + ASSERT(nbytes == sizeof info); } memcpy(&gHandler.currSignal, &info, sizeof info); gHandler.signals[info.si_signo] = SIG_SRC_SIGNALED; @@ -133,7 +134,7 @@ SignalSourceSigHandler(int signum, * have to be created... */ g_warning("Too many signals queued, this shouldn't happen.\n"); - g_assert(FALSE); + ASSERT(FALSE); } else { g_warning("Could not queue signal %d (error %d: %s)\n", signum, errno, strerror(errno)); @@ -264,8 +265,8 @@ VMTools_NewSignalSource(int signum) }; SignalSource *ret; - g_assert(signum < MAX_SIGNALS); - g_assert(signum != SIGKILL && signum != SIGSTOP); + ASSERT(signum < MAX_SIGNALS); + ASSERT(signum != SIGKILL && signum != SIGSTOP); G_LOCK(gLock); if (!gHandler.initialized) { @@ -273,7 +274,7 @@ VMTools_NewSignalSource(int signum) if (pipe(gHandler.wakeupPipe) == -1 || fcntl(gHandler.wakeupPipe[0], F_SETFL, O_RDONLY | O_NONBLOCK) < 0 || fcntl(gHandler.wakeupPipe[1], F_SETFL, O_WRONLY | O_NONBLOCK) < 0) { - g_assert(FALSE); + ASSERT(FALSE); } gHandler.wakeupFd.fd = gHandler.wakeupPipe[0]; gHandler.wakeupFd.events = G_IO_IN | G_IO_ERR; diff --git a/open-vm-tools/libvmtools/vmtools.c b/open-vm-tools/libvmtools/vmtools.c index e5eaf31e3..fde18b76f 100644 --- a/open-vm-tools/libvmtools/vmtools.c +++ b/open-vm-tools/libvmtools/vmtools.c @@ -43,8 +43,6 @@ VM_EMBED_VERSION(VMTOOLSLIB_VERSION_STRING); #endif -extern void VMTools_ResetLogging(gboolean cleanDefault); - /** * A convenience function for wrapping an array with a GArray instance. @@ -91,9 +89,9 @@ VMToolsDllInit(void *lib) VMTools_ResetLogging(FALSE); wiperData.resourceModule = lib; success = (NetUtil_LoadIpHlpApiDll() == ERROR_SUCCESS); - g_assert(success); + ASSERT(success); success = Wiper_Init(&wiperData); - g_assert(success); + ASSERT(success); #else VMTools_ResetLogging(FALSE); success = Wiper_Init(NULL); diff --git a/open-vm-tools/libvmtools/vmtoolsConfig.c b/open-vm-tools/libvmtools/vmtoolsConfig.c index f41408f90..944ee9d7d 100644 --- a/open-vm-tools/libvmtools/vmtoolsConfig.c +++ b/open-vm-tools/libvmtools/vmtoolsConfig.c @@ -72,6 +72,9 @@ VMToolsConfigUpgradeLog(GKeyFile *cfg, * and vmware-user. Instead of baking in the library whether we're * running one or the other, separate the two configurations, so that * the user can choose a different location for one or another. + * + * Also append the PID to the vmusr log path, since the old code did + * that automatically. */ gchar *userlog; @@ -82,7 +85,7 @@ VMToolsConfigUpgradeLog(GKeyFile *cfg, g_key_file_set_string(cfg, entry->destGroup, VMTOOLS_GUEST_SERVICE ".data", value); - userlog = g_strdup_printf("%s.user", value); + userlog = g_strdup_printf("%s.user.${PID}", value); g_key_file_set_string(cfg, entry->destGroup, VMTOOLS_USER_SERVICE ".handler", "file"); g_key_file_set_string(cfg, entry->destGroup, @@ -90,6 +93,12 @@ VMToolsConfigUpgradeLog(GKeyFile *cfg, g_key_file_set_string(cfg, entry->destGroup, VMTOOLS_USER_SERVICE ".data", userlog); + /* + * Keep the log.file entry since vmware-user is still using the old-style + * config. This can go away once it's ported over. + */ + g_key_file_set_string(cfg, entry->destGroup, CONFNAME_LOGFILE, value); + g_free(userlog); } @@ -131,10 +140,11 @@ VMToolsConfigUpgrade(GuestApp_Dict *old, for (entry = entries; entry->key != NULL; entry++) { const char *value = GuestApp_GetDictEntry(old, entry->key); const char *dfltValue = GuestApp_GetDictEntryDefault(old, entry->key); - + if (value == NULL || (dfltValue != NULL && strcmp(value, dfltValue) == 0)) { continue; } + switch (entry->type) { case CFG_BOOLEAN: { @@ -153,26 +163,16 @@ VMToolsConfigUpgrade(GuestApp_Dict *old, } case CFG_STRING: - { - const char *val = GuestApp_GetDictEntry(old, entry->key); - if (val != NULL) { - g_key_file_set_string(dst, entry->destGroup, entry->destKey, val); - } - break; - } + g_key_file_set_string(dst, entry->destGroup, entry->destKey, value); + break; case CFG_CALLBACK: - { - const char *val = GuestApp_GetDictEntry(old, entry->key); - if (val != NULL) { - g_assert(entry->data); - ((CfgCallback)entry->data)(dst, entry, val); - } - break; - } + ASSERT(entry->data); + ((CfgCallback)entry->data)(dst, entry, value); + break; default: - g_assert_not_reached(); + NOT_REACHED(); } } } @@ -200,7 +200,7 @@ VMTools_GetToolsConfFile(void) */ if (confPath == NULL) { confPath = GuestApp_GetConfPath(); - g_assert(confPath != NULL); + ASSERT(confPath != NULL); } confFilePath = g_strdup_printf("%s%c%s", confPath, DIRSEPC, CONF_FILE); free(confPath); @@ -327,11 +327,11 @@ VMTools_ReloadConfig(const gchar *path, gboolean ret = FALSE; GKeyFile *newConfig = NULL; - g_assert(config != NULL); - g_assert(mtime != NULL); + ASSERT(config != NULL); + ASSERT(mtime != NULL); if (g_stat(path, &confStat) == -1) { - g_warning("Failed to stat conf file: %s\n", strerror(errno)); + g_debug("Failed to stat conf file: %s\n", strerror(errno)); goto exit; } @@ -394,8 +394,8 @@ VMTools_WriteConfig(const gchar *path, FILE *out = NULL; GError *lerr = NULL; - g_assert(path != NULL); - g_assert(config != NULL); + ASSERT(path != NULL); + ASSERT(config != NULL); localPath = VMTOOLS_GET_FILENAME_LOCAL(path, &lerr); if (lerr != NULL) { diff --git a/open-vm-tools/libvmtools/vmtoolsLog.c b/open-vm-tools/libvmtools/vmtoolsLog.c index 759002fb3..cf6ff0544 100644 --- a/open-vm-tools/libvmtools/vmtoolsLog.c +++ b/open-vm-tools/libvmtools/vmtoolsLog.c @@ -96,13 +96,12 @@ VMToolsLogOutputDebugString(const gchar *domain, gpointer _data); #endif -void VMTools_ResetLogging(gboolean cleanDefault); - typedef struct LogHandlerData { gchar *domain; GLogLevelFlags mask; FILE *file; gchar *path; + gboolean append; guint handlerId; gboolean inherited; } LogHandlerData; @@ -122,12 +121,15 @@ static GPtrArray *gDomains = NULL; * present. Only one old log file is preserved. * * @param[in] path Path to log file. + * @param[in] append Whether to open the log for appending (if TRUE, a backup + * file is not generated). * * @return File pointer for writing to the file (NULL on error). */ static FILE * -VMToolsLogOpenFile(const gchar *path) +VMToolsLogOpenFile(const gchar *path, + gboolean append) { FILE *logfile = NULL; gchar *pathLocal; @@ -135,7 +137,7 @@ VMToolsLogOpenFile(const gchar *path) ASSERT(path != NULL); pathLocal = VMTOOLS_GET_FILENAME_LOCAL(path, NULL); - if (g_file_test(path, G_FILE_TEST_EXISTS)) { + if (!append && g_file_test(path, G_FILE_TEST_EXISTS)) { /* Back up existing log file. */ gchar *bakFile = g_strdup_printf("%s.old", pathLocal); if (!g_file_test(bakFile, G_FILE_TEST_IS_DIR) && @@ -146,7 +148,7 @@ VMToolsLogOpenFile(const gchar *path) g_free(bakFile); } - logfile = g_fopen(pathLocal, "w"); + logfile = g_fopen(pathLocal, append ? "a" : "w"); VMTOOLS_RELEASE_FILENAME_LOCAL(pathLocal); return logfile; } @@ -317,7 +319,7 @@ VMToolsLogFile(const gchar *domain, FILE *dest; data = data->inherited ? gDefaultData : data; if (data->file == NULL && data->path != NULL) { - data->file = VMToolsLogOpenFile(data->path); + data->file = VMToolsLogOpenFile(data->path, data->append); if (data->file == NULL) { g_warning("Unable to open log file %s for domain %s.\n", data->domain, data->path); @@ -396,7 +398,8 @@ VMToolsConfigLogDomain(const gchar *domain, } } else if (strcmp(handler, "std") == 0) { handlerFn = VMToolsLogFile; - } else if (strcmp(handler, "file") == 0) { + } else if (strcmp(handler, "file") == 0 || + strcmp(handler, "file+") == 0) { /* Don't set up the file sink if logging is disabled. */ if (strcmp(level, "none") != 0) { handlerFn = VMToolsLogFile; @@ -482,17 +485,33 @@ VMToolsConfigLogDomain(const gchar *domain, data->domain = g_strdup(domain); data->mask = levelsMask; data->path = logpath; + data->append = (handler != NULL && strcmp(handler, "file+") == 0); logpath = NULL; if (strcmp(domain, VMTools_GetDefaultLogDomain()) == 0) { - /* Replace the default log configuration before freeing the old data. */ + /* + * Replace the global log configuration. If the default log domain was + * logging to a file and the file path hasn't changed, then keep the old + * file handle open, instead of rotating the log. + */ LogHandlerData *old = gDefaultData; - LogHandlerData *gdata = g_malloc0(sizeof *gdata); - memcpy(gdata, data, sizeof *gdata); - g_log_set_default_handler(handlerFn, gdata); + if (old->file != NULL) { + ASSERT(old->path); + if (data->path != NULL && strcmp(data->path, old->path) == 0) { + g_free(data->path); + data->file = old->file; + data->path = old->path; + old->path = NULL; + } else { + fclose(old->file); + g_free(old->path); + } + } - gDefaultData = gdata; + g_log_set_default_handler(handlerFn, data); + gDefaultData = data; + data = NULL; gDefaultLogFunc = handlerFn; g_free(old); } else if (handler == NULL) { @@ -500,12 +519,14 @@ VMToolsConfigLogDomain(const gchar *domain, data->inherited = TRUE; } - if (gDomains == NULL) { - gDomains = g_ptr_array_new(); + if (data != NULL) { + if (gDomains == NULL) { + gDomains = g_ptr_array_new(); + } + g_ptr_array_add(gDomains, data); + data->handlerId = g_log_set_handler(domain, ALL_LOG_LEVELS | G_LOG_FATAL_MASK, + handlerFn, data); } - g_ptr_array_add(gDomains, data); - data->handlerId = g_log_set_handler(domain, ALL_LOG_LEVELS | G_LOG_FATAL_MASK, - handlerFn, data); exit: g_free(handler); @@ -539,7 +560,7 @@ VMTools_GetDefaultLogDomain(void) void VMTools_SetDefaultLogDomain(const gchar *domain) { - g_assert(domain != NULL); + ASSERT(domain != NULL); if (gLogDomain != NULL) { g_free(gLogDomain); } @@ -630,6 +651,8 @@ void VMTools_ResetLogging(gboolean cleanDefault) { gboolean oldLogEnabled = gLogEnabled; + gchar *currentPath = NULL; + FILE *currentFile = NULL; /* Disable logging while we're playing with the configuration. */ gLogEnabled = FALSE; @@ -655,6 +678,8 @@ VMTools_ResetLogging(gboolean cleanDefault) } if (gDefaultData != NULL) { + currentFile = gDefaultData->file; + currentPath = gDefaultData->path; g_free(gDefaultData); gDefaultData = NULL; } @@ -677,8 +702,15 @@ VMTools_ResetLogging(gboolean cleanDefault) #if defined(VMX86_DEBUG) gDefaultData->mask |= G_LOG_LEVEL_MESSAGE; #endif + gDefaultData->file = currentFile; + gDefaultData->path = currentPath; gLogEnabled = oldLogEnabled; g_log_set_default_handler(gDefaultLogFunc, gDefaultData); + } else { + if (currentFile != NULL) { + fclose(currentFile); + } + g_free(currentPath); } } diff --git a/open-vm-tools/modules/freebsd/shared/compat_freebsd.h b/open-vm-tools/modules/freebsd/shared/compat_freebsd.h index abce26be4..4bbb5d2ef 100644 --- a/open-vm-tools/modules/freebsd/shared/compat_freebsd.h +++ b/open-vm-tools/modules/freebsd/shared/compat_freebsd.h @@ -49,6 +49,8 @@ #include #include "compat_vop.h" +#include "compat_mount.h" +#include "compat_priv.h" /* * FreeBSD version 8 and above uses the kproc API instead of the kthread API in its diff --git a/open-vm-tools/modules/freebsd/shared/compat_mount.h b/open-vm-tools/modules/freebsd/shared/compat_mount.h new file mode 100644 index 000000000..5a823dab9 --- /dev/null +++ b/open-vm-tools/modules/freebsd/shared/compat_mount.h @@ -0,0 +1,58 @@ +/********************************************************* + * Copyright (C) 2009 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 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 GNU General Public License + * for more details. + * + * You should have received a copy of the GNU 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 + * + *********************************************************/ + +/********************************************************* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of VMware Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission of VMware Inc. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *********************************************************/ + +#ifndef __COMPAT_MOUNT_H__ +# define __COMPAT_MOUNT_H__ 1 + +#if __FreeBSD_version >= 800011 +#define COMPAT_VFS_STATFS(mp, sbp, threadvar) VFS_STATFS((mp), (sbp)) +#define compat_td curthread +#else +#define COMPAT_VFS_STATFS(mp, sbp, threadvar) VFS_STATFS((mp), (sbp), (threadvar)) +#define compat_td td +#endif + +#endif diff --git a/open-vm-tools/modules/freebsd/shared/compat_priv.h b/open-vm-tools/modules/freebsd/shared/compat_priv.h new file mode 100644 index 000000000..14ebfeb2c --- /dev/null +++ b/open-vm-tools/modules/freebsd/shared/compat_priv.h @@ -0,0 +1,56 @@ +/********************************************************* + * Copyright (C) 2009 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 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 GNU General Public License + * for more details. + * + * You should have received a copy of the GNU 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 + * + *********************************************************/ + +/********************************************************* + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of VMware Inc. nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission of VMware Inc. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + *********************************************************/ + +#ifndef __COMPAT_PRIV_H__ +# define __COMPAT_PRIV_H__ 1 + +#if __FreeBSD_version >= 800011 +#define compat_priv_check(td, priv) priv_check((td), (priv)) +#else +#define compat_priv_check(td, priv) suser(td) +#endif + +#endif diff --git a/open-vm-tools/modules/freebsd/shared/compat_vop.h b/open-vm-tools/modules/freebsd/shared/compat_vop.h index d37440112..43ecc69d5 100644 --- a/open-vm-tools/modules/freebsd/shared/compat_vop.h +++ b/open-vm-tools/modules/freebsd/shared/compat_vop.h @@ -54,6 +54,8 @@ #define compat_lockstatus(lock, threadvar) lockstatus((lock)) #define compat_lockmgr(lock, flags, randompointerparam, threadval) lockmgr((lock), (flags), (randompointerparam)) #define compat_vn_lock(vp, flags, threadval) vn_lock((vp), (flags)) +#define compat_accmode_t accmode_t +#define compat_a_accmode a_accmode #else #define COMPAT_THREAD_VAR(varname, varval) struct thread *varname = varval #define COMPAT_VOP_LOCK(vop, flags, threadvar) VOP_LOCK((vop), (flags), (threadvar)) @@ -61,6 +63,8 @@ #define compat_lockstatus(lock, threadvar) lockstatus((lock), (threadvar)) #define compat_vn_lock(vp, flags, threadval) vn_lock((vp), (flags), (threadval)) #define compat_lockmgr(lock, flags, randompointerparam, threadval) lockmgr((lock), (flags), (randompointerparam), (threadval)) +#define compat_accmode_t mode_t +#define compat_a_accmode a_mode #endif /* diff --git a/open-vm-tools/modules/freebsd/vmblock/subr.c b/open-vm-tools/modules/freebsd/vmblock/subr.c index 31166281e..23c6fc50a 100644 --- a/open-vm-tools/modules/freebsd/vmblock/subr.c +++ b/open-vm-tools/modules/freebsd/vmblock/subr.c @@ -56,6 +56,8 @@ #include #include +#include "compat_freebsd.h" + #include "vmblock_k.h" #include "block.h" @@ -181,11 +183,9 @@ static struct vnode * VMBlockHashGet(struct mount *mp, // IN: vmblock file system information struct vnode *lowervp) // IN: lower vnode to search for { - struct thread *td = curthread; /* XXX */ struct nodeHashHead *hd; struct VMBlockNode *a; struct vnode *vp; - int error; ASSERT_VOP_LOCKED(lowervp, "hashEntryget"); @@ -199,23 +199,14 @@ VMBlockHashGet(struct mount *mp, // IN: vmblock file system information mtx_lock(&hashMutex); LIST_FOREACH(a, hd, hashEntry) { if (a->lowerVnode == lowervp && VMBTOVP(a)->v_mount == mp) { - vp = VMBTOVP(a); - VI_LOCK(vp); - mtx_unlock(&hashMutex); - /* - * We need to clear the OWEINACT flag here as this may lead vget() - * to try to lock our vnode which is already locked via lowervp. - */ - vp->v_iflag &= ~VI_OWEINACT; - error = vget(vp, LK_INTERLOCK, td); /* * Since we have the lower node locked the nullfs node can not be * in the process of recycling. If it had been recycled before we * grabed the lower lock it would not have been found on the hash. */ - if (error) { - panic("hashEntryget: vget error %d", error); - } + vp = VMBTOVP(a); + vref(vp); + mtx_unlock(&hashMutex); return vp; } } @@ -246,11 +237,9 @@ static struct vnode * VMBlockHashInsert(struct mount *mp, // IN: VMBlock file system info struct VMBlockNode *xp) // IN: node to insert into hash { - struct thread *td = curthread; /* XXX */ struct nodeHashHead *hd; struct VMBlockNode *oxp; struct vnode *ovp; - int error; hd = VMBLOCK_NHASH(xp->lowerVnode); mtx_lock(&hashMutex); @@ -261,13 +250,8 @@ VMBlockHashInsert(struct mount *mp, // IN: VMBlock file system info * operation. */ ovp = VMBTOVP(oxp); - VI_LOCK(ovp); + vref(ovp); mtx_unlock(&hashMutex); - ovp->v_iflag &= ~VI_OWEINACT; - error = vget(ovp, LK_INTERLOCK, td); - if (error) { - panic("hashEntryins: vget error %d", error); - } return ovp; } } @@ -326,9 +310,9 @@ VMBlockInsMntQueDtr(struct vnode *vp, // IN: node to cleanup { vp->v_data = NULL; vp->v_vnlock = &vp->v_lock; - FREE(xp, M_VMBLOCKFSNODE); + free(xp, M_VMBLOCKFSNODE); vp->v_op = &dead_vnodeops; - (void) vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread); + (void) compat_vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, curthread); vgone(vp); vput(vp); } @@ -617,13 +601,6 @@ VMBlockDestroyBlockName(char *blockName) // IN: name to free #ifdef DIAGNOSTIC /* if (DIAGNOSTIC) { */ -#ifdef KDB /* if (KDB) { */ -# define VMBlockCheckVp_barrier 1 -#else -# define VMBlockCheckVp_barrier 0 -#endif /* } */ - - /* *----------------------------------------------------------------------------- * @@ -659,7 +636,6 @@ VMBlockCheckVp(vp, fil, lno) */ if (vp->v_op != null_vnodeop_p) { printf ("VMBlockCheckVp: on non-null-node\n"); - while (VMBlockCheckVp_barrier) /*WAIT*/ ; panic("VMBlockCheckVp"); }; #endif @@ -671,8 +647,6 @@ VMBlockCheckVp(vp, fil, lno) printf(" %lx", p[i]); } printf("\n"); - /* wait for debugger */ - while (VMBlockCheckVp_barrier) /*WAIT*/ ; panic("VMBlockCheckVp"); } if (vrefcnt(a->lowerVnode) < 1) { @@ -682,8 +656,6 @@ VMBlockCheckVp(vp, fil, lno) printf(" %lx", p[i]); } printf("\n"); - /* wait for debugger */ - while (VMBlockCheckVp_barrier) /*WAIT*/ ; panic ("null with unref'ed lowervp"); }; #ifdef notyet diff --git a/open-vm-tools/modules/freebsd/vmblock/vfsops.c b/open-vm-tools/modules/freebsd/vmblock/vfsops.c index 37bcaf133..a430b6193 100644 --- a/open-vm-tools/modules/freebsd/vmblock/vfsops.c +++ b/open-vm-tools/modules/freebsd/vmblock/vfsops.c @@ -113,8 +113,12 @@ VFS_SET(VMBlockVFSOps, vmblock, VFCF_LOOPBACK); */ static int -VMBlockVFSMount(struct mount *mp, // IN: mount(2) parameters - struct thread *td) // IN: caller's kernel thread context +#if __FreeBSD_version >= 800011 +VMBlockVFSMount(struct mount *mp) // IN: mount(2) parameters +#else +VMBlockVFSMount(struct mount *mp, // IN: mount(2) parameters + struct thread *td) // IN: caller's thread context +#endif { struct VMBlockMount *xmp; struct nameidata nd, *ndp = &nd; @@ -158,7 +162,8 @@ VMBlockVFSMount(struct mount *mp, // IN: mount(2) parameters /* * Find lower node and lock if not already locked. */ - NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target, td); + + NDINIT(ndp, LOOKUP, FOLLOW|LOCKLEAF, UIO_SYSSPACE, target, compat_td); error = namei(ndp); if (error) { NDFREE(ndp, 0); @@ -189,7 +194,7 @@ VMBlockVFSMount(struct mount *mp, // IN: mount(2) parameters * Make sure the node alias worked */ if (error) { - COMPAT_VOP_UNLOCK(vp, 0, td); + COMPAT_VOP_UNLOCK(vp, 0, compat_td); vrele(lowerrootvp); free(xmp, M_VMBLOCKFSMNT); /* XXX */ return error; @@ -211,7 +216,7 @@ VMBlockVFSMount(struct mount *mp, // IN: mount(2) parameters /* * Unlock the node (either the lower or the alias) */ - COMPAT_VOP_UNLOCK(vp, 0, td); + COMPAT_VOP_UNLOCK(vp, 0, compat_td); /* * If the staging area is a local filesystem, reflect that here, too. (We @@ -253,9 +258,14 @@ VMBlockVFSMount(struct mount *mp, // IN: mount(2) parameters */ static int -VMBlockVFSUnmount(struct mount *mp, // IN: filesystem to unmount - int mntflags, // IN: unmount(2) flags (ex: MNT_FORCE) - struct thread *td) // IN: caller's kernel thread context +#if __FreeBSD_version >= 800011 +VMBlockVFSUnmount(struct mount *mp, // IN: filesystem to unmount + int mntflags) // IN: unmount(2) flags (ex: MNT_FORCE) +#else +VMBlockVFSUnmount(struct mount *mp, // IN: filesystem to unmount + int mntflags, // IN: unmount(2) flags (ex: MNT_FORCE) + struct thread *td) // IN: caller's kernel thread context +#endif { struct VMBlockMount *xmp; struct vnode *vp; @@ -290,21 +300,21 @@ VMBlockVFSUnmount(struct mount *mp, // IN: filesystem to unmount * transfer will happen atomically. (Er, at least within the scope of * the vnode subsystem.) */ - COMPAT_VOP_LOCK(vp, LK_EXCLUSIVE|LK_RETRY|LK_INTERLOCK, td); + COMPAT_VOP_LOCK(vp, LK_EXCLUSIVE|LK_RETRY|LK_INTERLOCK, compat_td); removed = BlockRemoveAllBlocks(OS_UNKNOWN_BLOCKER); VI_LOCK(vp); vp->v_usecount -= removed; VI_UNLOCK(vp); - COMPAT_VOP_UNLOCK(vp, 0, td); + COMPAT_VOP_UNLOCK(vp, 0, compat_td); if (mntflags & MNT_FORCE) { flags |= FORCECLOSE; } /* There is 1 extra root vnode reference (xmp->rootVnode). */ - error = vflush(mp, 1, flags, td); + error = vflush(mp, 1, flags, compat_td); if (error) { return error; } @@ -336,10 +346,16 @@ VMBlockVFSUnmount(struct mount *mp, // IN: filesystem to unmount */ static int +#if __FreeBSD_version >= 800011 +VMBlockVFSRoot(struct mount *mp, // IN: vmblock file system + int flags, // IN: lockmgr(9) flags + struct vnode **vpp) // OUT: root vnode +#else VMBlockVFSRoot(struct mount *mp, // IN: vmblock file system int flags, // IN: lockmgr(9) flags struct vnode **vpp, // OUT: root vnode struct thread *td) // IN: caller's thread context +#endif { struct vnode *vp; @@ -348,7 +364,7 @@ VMBlockVFSRoot(struct mount *mp, // IN: vmblock file system */ vp = MNTTOVMBLOCKMNT(mp)->rootVnode; VREF(vp); - compat_vn_lock(vp, flags | LK_RETRY, td); + compat_vn_lock(vp, flags | LK_RETRY, compat_td); *vpp = vp; return 0; } @@ -373,9 +389,14 @@ VMBlockVFSRoot(struct mount *mp, // IN: vmblock file system */ static int +#if __FreeBSD_version >= 800011 +VMBlockVFSStatFS(struct mount *mp, // IN: vmblock file system + struct statfs *sbp) // OUT: statfs(2) arg container +#else VMBlockVFSStatFS(struct mount *mp, // IN: vmblock file system struct statfs *sbp, // OUT: statfs(2) arg container struct thread *td) // IN: caller's thread context +#endif { int error; struct statfs mstat; @@ -386,7 +407,7 @@ VMBlockVFSStatFS(struct mount *mp, // IN: vmblock file system bzero(&mstat, sizeof mstat); - error = VFS_STATFS(MNTTOVMBLOCKMNT(mp)->mountVFS, &mstat, td); + error = COMPAT_VFS_STATFS(MNTTOVMBLOCKMNT(mp)->mountVFS, &mstat, compat_td); if (error) { return error; } @@ -423,9 +444,14 @@ VMBlockVFSStatFS(struct mount *mp, // IN: vmblock file system */ static int +#if __FreeBSD_version >= 800011 +VMBlockVFSSync(struct mount *mp, // Ignored + int waitfor) // Ignored +#else VMBlockVFSSync(struct mount *mp, // Ignored int waitfor, // Ignored struct thread *td) // Ignored +#endif { return 0; } diff --git a/open-vm-tools/modules/freebsd/vmblock/vnops.c b/open-vm-tools/modules/freebsd/vmblock/vnops.c index 3fc69c611..c9241e15c 100644 --- a/open-vm-tools/modules/freebsd/vmblock/vnops.c +++ b/open-vm-tools/modules/freebsd/vmblock/vnops.c @@ -751,8 +751,11 @@ struct vop_open_args { * * NB: Allowing only the superuser to open this directory breaks * readdir() of the filesystem root for non-privileged users. + * + * Also, on FreeBSD 8.0 and newer we check for a specific module priv + * because none of the existing privs seemed to match very well. */ - if ((retval = suser(ap->a_td)) == 0) { + if ((retval = compat_priv_check(ap->a_td, PRIV_DRIVER)) == 0) { #if __FreeBSD_version >= 700055 fp = ap->a_fp; #else @@ -1036,7 +1039,7 @@ struct vop_access_args { */ { struct vnode *vp = ap->a_vp; - mode_t mode = ap->a_mode; + compat_accmode_t mode = ap->compat_a_accmode; /* * Disallow write attempts on read-only layers; unless the file is a diff --git a/open-vm-tools/modules/freebsd/vmmemctl/os.c b/open-vm-tools/modules/freebsd/vmmemctl/os.c index af1da72ce..b99761d87 100644 --- a/open-vm-tools/modules/freebsd/vmmemctl/os.c +++ b/open-vm-tools/modules/freebsd/vmmemctl/os.c @@ -16,12 +16,10 @@ * *********************************************************/ -/* +/* * os.c -- * - * Wrappers for FreeBSD system functions required by "vmmemctl". - * This allows customers to build their own vmmemctl driver for - * custom FreeBSD kernels without the need for source code. + * Wrappers for FreeBSD system functions required by "vmmemctl". */ /* @@ -73,14 +71,14 @@ typedef struct { volatile int stop; /* registered state */ - os_timer_handler handler; + OSTimerHandler *handler; void *data; int period; } os_timer; typedef struct { /* registered state */ - os_status_handler handler; + OSStatusHandler *handler; const char *name_verbose; const char *name; } os_status; @@ -109,26 +107,99 @@ static os_state global_state; static void vmmemctl_init_sysctl(void); static void vmmemctl_deinit_sysctl(void); + /* - * Simple Wrappers + *----------------------------------------------------------------------------- + * + * OS_Malloc -- + * + * Allocates kernel memory. + * + * Results: + * On success: Pointer to allocated memory + * On failure: NULL + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- */ -void *os_kmalloc_nosleep(unsigned int size) +void * +OS_Malloc(size_t size) // IN { return(malloc(size, M_VMMEMCTL, M_NOWAIT)); } -void os_kfree(void *obj, unsigned int size) + +/* + *----------------------------------------------------------------------------- + * + * OS_Free -- + * + * Free allocated kernel memory. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +OS_Free(void *ptr, // IN + size_t size) // IN { - free(obj, M_VMMEMCTL); + free(ptr, M_VMMEMCTL); } -void os_bzero(void *b, unsigned int len) + +/* + *----------------------------------------------------------------------------- + * + * OS_MemZero -- + * + * Fill a memory location with 0s. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +OS_MemZero(void *ptr, // OUT + size_t size) // IN { - bzero(b, len); + bzero(ptr, size); } -void os_memcpy(void *dest, const void *src, unsigned int size) + +/* + *----------------------------------------------------------------------------- + * + * OS_MemCopy -- + * + * Copy a memory portion into another location. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +OS_MemCopy(void *dest, // OUT + const void *src, // IN + size_t size) // IN { memcpy(dest, src, size); } @@ -148,18 +219,45 @@ static __inline__ unsigned long os_ffz(unsigned long word) return word; } -int os_sprintf(char *str, const char *format, ...) + +/* + *----------------------------------------------------------------------------- + * + * OS_Snprintf -- + * + * Print a string into a bounded memory location. + * + * Results: + * Number of character printed including trailing \0. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +int +OS_Snprintf(char *buf, // OUT + size_t size, // IN + const char *format, // IN + ...) // IN { + int result; va_list args; + va_start(args, format); - return(vsprintf(str, format, args)); + result = vsnprintf(buf, size, format, args); + va_end(args); + + return result; } /* * System-Dependent Operations */ -char *os_identity(void) +const char * +OS_Identity(void) { return("bsd"); } @@ -169,12 +267,14 @@ char *os_identity(void) * * Currently we just return the total memory pages. */ -unsigned int os_predict_max_balloon_pages(void) +unsigned int +OS_PredictMaxReservedPages(void) { return(cnt.v_page_count); } -unsigned long os_addr_to_ppn(unsigned long addr) +unsigned long +OS_AddrToPPN(unsigned long addr) { return (((vm_page_t)addr)->phys_addr) >> PAGE_SHIFT; } @@ -308,16 +408,18 @@ static void os_balloonobject_delete(void) static void os_balloonobject_create(void) { - global_state.vmobject = vm_object_allocate(OBJT_DEFAULT, + global_state.vmobject = vm_object_allocate(OBJT_DEFAULT, OFF_TO_IDX(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS)); } -unsigned long os_alloc_reserved_page(int can_sleep) +unsigned long +OS_AllocReservedPage(int canSleep) { - return (unsigned long)os_kmem_alloc(can_sleep); + return (unsigned long)os_kmem_alloc(canSleep); } -void os_free_reserved_page(unsigned long page) +void +OS_FreeReservedPage(unsigned long page) { os_kmem_free((vm_page_t)page); } @@ -333,18 +435,22 @@ static void os_timer_internal(void *data) } } -void os_timer_init(os_timer_handler handler, void *data, int period) +void +OS_TimerInit(OSTimerHandler *handler, // IN + void *clientData, // IN + int period) // IN { os_timer *t = &global_state.timer; callout_handle_init(&t->callout_handle); t->handler = handler; - t->data = data; + t->data = clientData; t->period = period; t->stop = 0; } -void os_timer_start(void) +void +OS_TimerStart(void) { os_timer *t = &global_state.timer; @@ -355,7 +461,8 @@ void os_timer_start(void) t->callout_handle = timeout(os_timer_internal, t, t->period); } -void os_timer_stop(void) +void +OS_TimerStop(void) { os_timer *t = &global_state.timer; @@ -366,19 +473,39 @@ void os_timer_stop(void) untimeout(os_timer_internal, t, t->callout_handle); } -unsigned int os_timer_hz(void) +unsigned int +OS_TimerHz(void) { return hz; } -void os_yield(void) + +/* + *----------------------------------------------------------------------------- + * + * OS_Yield -- + * + * Yield the CPU, if needed. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +OS_Yield(void) { /* Do nothing. */ } -void os_init(const char *name, - const char *name_verbose, - os_status_handler handler) +void +OS_Init(const char *name, + const char *name_verbose, + OSStatusHandler *handler) { os_state *state = &global_state; os_pmap *pmap = &state->pmap; @@ -409,7 +536,8 @@ void os_init(const char *name, printf("%s initialized\n", state->status.name_verbose); } -void os_cleanup(void) +void +OS_Cleanup(void) { os_state *state = &global_state; os_pmap *pmap = &state->pmap; @@ -485,7 +613,7 @@ vmmemctl_sysctl(SYSCTL_HANDLER_ARGS) char stats[PAGE_SIZE]; size_t len; - len = 1 + global_state.status.handler(stats); + len = 1 + global_state.status.handler(stats, PAGE_SIZE); return SYSCTL_OUT(req, stats, len); } diff --git a/open-vm-tools/modules/freebsd/vmmemctl/os.h b/open-vm-tools/modules/freebsd/vmmemctl/os.h index 8a5f690e6..b991edd71 100644 --- a/open-vm-tools/modules/freebsd/vmmemctl/os.h +++ b/open-vm-tools/modules/freebsd/vmmemctl/os.h @@ -16,62 +16,49 @@ * *********************************************************/ -/* +/* * os.h -- * - * Definitions for OS-specific wrapper functions required - * by "vmmemctl". This allows customers to build their own - * vmmemctl driver for custom versioned kernels without the - * need for source code. + * Definitions for OS-specific wrapper functions required by "vmmemctl". */ #ifndef OS_H #define OS_H -/* - * Needs fixing for 64bit OSes - */ -#ifndef __x86_64__ -#define CDECL __attribute__((cdecl, regparm(0))) -#else -#define CDECL -#endif - /* * Types */ -typedef void CDECL (*os_timer_handler)(void *); -typedef int CDECL (*os_status_handler)(char *); +typedef void OSTimerHandler(void *clientData); +typedef int OSStatusHandler(char *buf, size_t size); /* * Operations */ -extern void CDECL *os_kmalloc_nosleep(unsigned int size); -extern void CDECL os_kfree(void *obj, unsigned int size); -extern void CDECL os_yield(void); -extern void CDECL os_bzero(void *s, unsigned int n); -extern void CDECL os_memcpy(void *dest, const void *src, unsigned int size); -extern int CDECL os_sprintf(char *str, const char *format, ...); - -extern unsigned long CDECL os_addr_to_ppn(unsigned long addr); -extern unsigned long CDECL os_alloc_reserved_page(int can_sleep); -extern void CDECL os_free_reserved_page(unsigned long page); +extern void OS_Init(const char *name, + const char *nameVerbose, + OSStatusHandler *handler); +extern void OS_Cleanup(void); +extern const char *OS_Identity(void); -extern void CDECL os_timer_init(os_timer_handler handler, void *data, int period); -extern void CDECL os_timer_start(void); -extern void CDECL os_timer_stop(void); +extern void OS_MemZero(void *ptr, size_t size); +extern void OS_MemCopy(void *dest, const void *src, size_t size); +extern int OS_Snprintf(char *buf, size_t size, const char *format, ...); -extern void CDECL os_init(const char *name, - const char *name_verbose, - os_status_handler handler); -extern void CDECL os_cleanup(void); +extern void *OS_Malloc(size_t size); +extern void OS_Free(void *ptr, size_t size); -extern char CDECL *os_identity(void); +extern void OS_Yield(void); -extern unsigned int CDECL os_predict_max_balloon_pages(void); +extern unsigned int OS_TimerHz(void); +extern void OS_TimerInit(OSTimerHandler *handler, void *clientData, int period); +extern void OS_TimerStart(void); +extern void OS_TimerStop(void); -extern unsigned int CDECL os_timer_hz(void); +extern unsigned int OS_PredictMaxReservedPages(void); +extern unsigned long OS_AddrToPPN(unsigned long addr); +extern unsigned long OS_AllocReservedPage(int canSleep); +extern void OS_FreeReservedPage(unsigned long page); #endif /* OS_H */ diff --git a/open-vm-tools/modules/freebsd/vmmemctl/vmballoon.c b/open-vm-tools/modules/freebsd/vmmemctl/vmballoon.c index a88eea718..91212ec8f 100644 --- a/open-vm-tools/modules/freebsd/vmmemctl/vmballoon.c +++ b/open-vm-tools/modules/freebsd/vmmemctl/vmballoon.c @@ -16,18 +16,18 @@ * *********************************************************/ -/* +/* * vmballoon.c -- * - * VMware server physical memory management driver for Unix-ish - * (Linux, FreeBSD, Solaris) guests. The driver acts like a - * "balloon" that can be inflated to reclaim physical pages by - * reserving them in the guest and invalidating them in the - * monitor, freeing up the underlying machine pages so they can - * be allocated to other guests. The balloon can also be - * deflated to allow the guest to use more physical memory. - * Higher level policies can control the sizes of balloons in VMs - * in order to manage physical memory resources. + * VMware physical memory management driver for Unix-ish + * (Linux, FreeBSD, Solaris, Mac OS) guests. The driver acts like + * a "balloon" that can be inflated to reclaim physical pages by + * reserving them in the guest and invalidating them in the + * monitor, freeing up the underlying machine pages so they can + * be allocated to other guests. The balloon can also be + * deflated to allow the guest to use more physical memory. + * Higher level policies can control the sizes of balloons in VMs + * in order to manage physical memory resources. */ #ifdef __cplusplus @@ -38,12 +38,12 @@ extern "C" { * Compile-Time Options */ -#define BALLOON_RATE_ADAPT (1) +#define BALLOON_RATE_ADAPT (1) -#define BALLOON_DEBUG (1) -#define BALLOON_DEBUG_VERBOSE (0) +#define BALLOON_DEBUG (1) +#define BALLOON_DEBUG_VERBOSE (0) -#define BALLOON_STATS +#define BALLOON_STATS #define BALLOON_STATS_PROCFS /* @@ -65,38 +65,38 @@ extern "C" { #define NULL 0 #endif -#define BALLOON_NAME "vmmemctl" -#define BALLOON_NAME_VERBOSE "VMware memory control driver" +#define BALLOON_NAME "vmmemctl" +#define BALLOON_NAME_VERBOSE "VMware memory control driver" -#define BALLOON_PROTOCOL_VERSION (2) +#define BALLOON_PROTOCOL_VERSION (2) -#define BALLOON_CHUNK_PAGES (1000) +#define BALLOON_CHUNK_PAGES (1000) -#define BALLOON_NOSLEEP_ALLOC_MAX (16384) +#define BALLOON_NOSLEEP_ALLOC_MAX (16384) -#define BALLOON_RATE_ALLOC_MIN (512) -#define BALLOON_RATE_ALLOC_MAX (2048) -#define BALLOON_RATE_ALLOC_INC (16) +#define BALLOON_RATE_ALLOC_MIN (512) +#define BALLOON_RATE_ALLOC_MAX (2048) +#define BALLOON_RATE_ALLOC_INC (16) -#define BALLOON_RATE_FREE_MIN (512) -#define BALLOON_RATE_FREE_MAX (16384) -#define BALLOON_RATE_FREE_INC (16) +#define BALLOON_RATE_FREE_MIN (512) +#define BALLOON_RATE_FREE_MAX (16384) +#define BALLOON_RATE_FREE_INC (16) -#define BALLOON_ERROR_PAGES (16) +#define BALLOON_ERROR_PAGES (16) -/* +/* * When guest is under memory pressure, use a reduced page allocation * rate for next several cycles. */ -#define SLOW_PAGE_ALLOCATION_CYCLES (4) +#define SLOW_PAGE_ALLOCATION_CYCLES (4) -/* +/* * Move it to bora/public/balloon_def.h later, if needed. Note that * BALLOON_PAGE_ALLOC_FAILURE is an internal error code used for * distinguishing page allocation failures from monitor-backdoor errors. * We use value 1000 because all monitor-backdoor error codes are < 1000. */ -#define BALLOON_PAGE_ALLOC_FAILURE (1000) +#define BALLOON_PAGE_ALLOC_FAILURE (1000) // Maximum number of page allocations without yielding processor #define BALLOON_ALLOC_YIELD_THRESHOLD (1024) @@ -156,7 +156,7 @@ static Balloon globalBalloon; static int BalloonGuestType(void); static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep); -static void BalloonPrimFreePage(unsigned long page); +static void BalloonPrimFreePage(unsigned long page); static int Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType); static int Balloon_FreePage(Balloon *b, int monitorUnlock); @@ -165,7 +165,7 @@ static void Balloon_Reset(Balloon *b); static void Balloon_StartTimer(Balloon *b); static void Balloon_StopTimer(Balloon *b); -static void CDECL Balloon_BH(void *data); +static void BalloonTimerHandler(void *clientData); static int Balloon_MonitorStart(Balloon *b); static int Balloon_MonitorGuestType(Balloon *b); @@ -177,51 +177,43 @@ static int Balloon_MonitorUnlockPage(Balloon *b, unsigned long addr); * Macros */ -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif - -#ifdef BALLOON_STATS -#define STATS_INC(stat) (stat)++ +#ifdef BALLOON_STATS +#define STATS_INC(stat) (stat)++ #else -#define STATS_INC(stat) +#define STATS_INC(stat) #endif /* * Macros to generate operations for simple lists of OBJ. * OBJ must contain next and prev fields. - * */ -#define GENERATE_LIST_INSERT(OBJ) \ -static void OBJ ## _Insert(OBJ **head, OBJ *obj) \ -{ \ - OBJ *h = *head; \ - \ - /* add element to head of list */ \ - obj->next = h; \ - if (h != NULL) { \ - h->prev = obj; \ - } \ - *head = obj; \ - obj->prev = NULL; \ +#define GENERATE_LIST_INSERT(OBJ) \ +static void OBJ ## _Insert(OBJ **head, OBJ *obj) \ +{ \ + OBJ *h = *head; \ + \ + /* add element to head of list */ \ + obj->next = h; \ + if (h != NULL) { \ + h->prev = obj; \ + } \ + *head = obj; \ + obj->prev = NULL; \ } -#define GENERATE_LIST_REMOVE(OBJ) \ -static void OBJ ## _Remove(OBJ **head, OBJ *obj) \ -{ \ - /* splice element out of list */ \ - if (obj->prev != NULL) { \ - obj->prev->next = obj->next; \ - } else { \ - *head = obj->next; \ - } \ - if (obj->next != NULL) { \ - obj->next->prev = obj->prev; \ - } \ +#define GENERATE_LIST_REMOVE(OBJ) \ +static void OBJ ## _Remove(OBJ **head, OBJ *obj) \ +{ \ + /* splice element out of list */ \ + if (obj->prev != NULL) { \ + obj->prev->next = obj->next; \ + } else { \ + *head = obj->next; \ + } \ + if (obj->next != NULL) { \ + obj->next->prev = obj->prev; \ + } \ } /* @@ -235,25 +227,28 @@ GENERATE_LIST_REMOVE(BalloonChunk); * Procfs Operations */ + /* *---------------------------------------------------------------------- * * BalloonProcRead -- * * Ballon driver status reporting routine. Note that this is only - * used for Linux. + * used for Linux. * * Results: * Writes ASCII status information into "buf". - * Returns number of bytes written. + * Returns number of bytes written. * * Side effects: * None. * *---------------------------------------------------------------------- */ -static int CDECL -BalloonProcRead(char *buf) + +static int +BalloonProcRead(char *buf, // OUT + size_t size) // IN { int len = 0; BalloonStats stats; @@ -261,14 +256,14 @@ BalloonProcRead(char *buf) BalloonGetStats(&stats); /* format size info */ - len += os_sprintf(buf + len, + len += OS_Snprintf(buf + len, size - len, "target: %8d pages\n" "current: %8d pages\n", stats.nPagesTarget, stats.nPages); /* format rate info */ - len += os_sprintf(buf + len, + len += OS_Snprintf(buf + len, size - len, "rateNoSleepAlloc: %8d pages/sec\n" "rateSleepAlloc: %8d pages/sec\n" "rateFree: %8d pages/sec\n", @@ -276,8 +271,8 @@ BalloonProcRead(char *buf) stats.rateAlloc, stats.rateFree); -#ifdef BALLOON_STATS_PROCFS - len += os_sprintf(buf + len, +#ifdef BALLOON_STATS_PROCFS + len += OS_Snprintf(buf + len, size - len, "\n" "timer: %8u\n" "start: %8u (%4u failed)\n" @@ -305,7 +300,7 @@ BalloonProcRead(char *buf) stats.primErrorPageFree); #endif - return(len); + return len; } /* @@ -318,7 +313,7 @@ BalloonProcRead(char *buf) * AddrToPPN -- * * Return the physical page number corresponding to the specified - * Linux kernel-mapped address. + * kernel-mapped address. * * Results: * Returns PPN for "addr". @@ -331,7 +326,7 @@ BalloonProcRead(char *buf) static inline unsigned long AddrToPPN(unsigned long addr) { - return(os_addr_to_ppn(addr)); + return OS_AddrToPPN(addr); } /* @@ -341,12 +336,12 @@ AddrToPPN(unsigned long addr) * * Attempts to allocate and reserve a physical page. * - * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP: - * The allocation can wait (sleep) for page writeout (swap) - * by the guest. - * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP: - * If allocation of a page requires disk writeout, then - * just fail. DON'T sleep. + * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP: + * The allocation can wait (sleep) for page writeout (swap) + * by the guest. + * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP: + * If allocation of a page requires disk writeout, then + * just fail. DON'T sleep. * * Results: * Returns the physical address of the allocated page, or 0 if error. @@ -359,7 +354,7 @@ AddrToPPN(unsigned long addr) static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep) { - return(os_alloc_reserved_page(canSleep)); + return OS_AllocReservedPage(canSleep); } /* @@ -380,7 +375,7 @@ BalloonPrimAllocPage(BalloonPageAllocType canSleep) static void BalloonPrimFreePage(unsigned long page) { - return(os_free_reserved_page(page)); + return OS_FreeReservedPage(page); } /* @@ -389,7 +384,7 @@ BalloonPrimFreePage(unsigned long page) * BalloonGuestType -- * * Return balloon guest OS identifier obtained by parsing - * system-dependent identity string. + * system-dependent identity string. * * Results: * Returns one of BALLOON_GUEST_{LINUX,BSD,SOLARIS,UNKNOWN}. @@ -402,11 +397,11 @@ BalloonPrimFreePage(unsigned long page) static int BalloonGuestType(void) { - char *identity; + const char *identity; /* obtain OS identify string */ - identity = os_identity(); - + identity = OS_Identity(); + /* unknown if not specified */ if (identity == NULL) { return(BALLOON_GUEST_UNKNOWN); @@ -416,19 +411,19 @@ BalloonGuestType(void) switch (identity[0]) { case 'l': case 'L': - return(BALLOON_GUEST_LINUX); + return BALLOON_GUEST_LINUX; case 'b': case 'B': - return(BALLOON_GUEST_BSD); + return BALLOON_GUEST_BSD; case 's': case 'S': - return(BALLOON_GUEST_SOLARIS); + return BALLOON_GUEST_SOLARIS; default: break; } /* unknown */ - return(BALLOON_GUEST_UNKNOWN); + return BALLOON_GUEST_UNKNOWN; } /* @@ -443,7 +438,7 @@ void BalloonGetStats(BalloonStats *stats) /* * Copy statistics out of global structure. */ - os_memcpy(stats, &b->stats, sizeof (BalloonStats)); + OS_MemCopy(stats, &b->stats, sizeof (BalloonStats)); /* * Fill in additional information about size and rates, which is @@ -465,37 +460,41 @@ void BalloonGetStats(BalloonStats *stats) * BalloonChunk_Create -- * * Creates a new BalloonChunk object capable of tracking - * BALLOON_CHUNK_PAGES PPNs. + * BALLOON_CHUNK_PAGES PPNs. * - * We do not bother to define two versions (NOSLEEP and CANSLEEP) - * of os_kmalloc because Chunk_Create does not require a new page - * often. + * We do not bother to define two versions (NOSLEEP and CANSLEEP) + * of OS_Malloc because Chunk_Create does not require a new page + * often. * * Results: - * Returns initialized BalloonChunk, or NULL if error. + * On success: initialized BalloonChunk + * On failure: NULL * * Side effects: - * None. + * None * *---------------------------------------------------------------------- */ + static BalloonChunk * BalloonChunk_Create(void) { BalloonChunk *chunk; /* allocate memory, fail if unable */ - if ((chunk = (BalloonChunk *) os_kmalloc_nosleep(sizeof(BalloonChunk))) == NULL) { - return(NULL); + chunk = OS_Malloc(sizeof *chunk); + if (chunk == NULL) { + return NULL; } /* initialize */ - os_bzero(chunk, sizeof(BalloonChunk)); + OS_MemZero(chunk, sizeof *chunk); /* everything OK */ - return(chunk); + return chunk; } + /* *---------------------------------------------------------------------- * @@ -515,7 +514,7 @@ static void BalloonChunk_Destroy(BalloonChunk *chunk) { /* reclaim storage */ - os_kfree(chunk, sizeof (BalloonChunk)); + OS_Free(chunk, sizeof *chunk); } /* @@ -542,7 +541,7 @@ static int Balloon_Init(Balloon *b) { /* clear state */ - os_bzero(b, sizeof(Balloon)); + OS_MemZero(b, sizeof *b); /* initialize rates */ b->rateAlloc = BALLOON_RATE_ALLOC_MAX; @@ -580,7 +579,7 @@ Balloon_Deallocate(Balloon *b) (void) Balloon_FreePage(b, FALSE); if (++cnt >= b->rateFree) { cnt = 0; - os_yield(); + OS_Yield(); } } } @@ -591,7 +590,7 @@ Balloon_Deallocate(Balloon *b) * Balloon_Reset -- * * Resets balloon "b" to empty state. Frees all allocated pages - * and attempts to reset contact with the monitor. + * and attempts to reset contact with the monitor. * * Results: * None. @@ -623,12 +622,12 @@ Balloon_Reset(Balloon *b) /* *---------------------------------------------------------------------- * - * Balloon_BH -- + * BalloonTimerHandler -- * * Balloon bottom half handler. Contacts monitor via backdoor - * to obtain balloon size target, and starts adjusting balloon - * size to achieve target by allocating or deallocating pages. - * Resets balloon if requested by the monitor. + * to obtain balloon size target, and starts adjusting balloon + * size to achieve target by allocating or deallocating pages. + * Resets balloon if requested by the monitor. * * Results: * None. @@ -638,10 +637,10 @@ Balloon_Reset(Balloon *b) * *---------------------------------------------------------------------- */ -static void CDECL -Balloon_BH(void *data) +static void +BalloonTimerHandler(void *clientData) { - Balloon *b = (Balloon *) data; + Balloon *b = (Balloon *) clientData; uint32 target; int status; @@ -679,14 +678,14 @@ Balloon_BH(void *data) * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ static void Balloon_StartTimer(Balloon *b) { - os_timer_start(); + OS_TimerStart(); } /* @@ -700,14 +699,14 @@ Balloon_StartTimer(Balloon *b) * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ static void Balloon_StopTimer(Balloon *b) { - os_timer_stop(); + OS_TimerStop(); } @@ -717,14 +716,14 @@ Balloon_StopTimer(Balloon *b) * Balloon_ErrorPagesAlloc -- * * Attempt to add "page" to list of non-balloonable pages - * associated with "b". + * associated with "b". * * Results: - * Returns BALLOON_SUCCESS iff successful, or BALLOON_FAILURE - * if non-balloonable page list is already full. + * On success: BALLOON_SUCCESS + * On failure: BALLOON_FAILURE (non-balloonable page list is already full) * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -749,13 +748,13 @@ Balloon_ErrorPagesAlloc(Balloon *b, unsigned long page) * Balloon_ErrorPagesFree -- * * Deallocates all pages on the list of non-balloonable pages - * associated with "b". + * associated with "b". * * Results: - * None. + * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -766,7 +765,7 @@ Balloon_ErrorPagesFree(Balloon *b) /* free all non-balloonable "error" pages */ for (i = 0; i < b->errors.nextPage; i++) { - BalloonPrimFreePage(b->errors.page[i]); + BalloonPrimFreePage(b->errors.page[i]); b->errors.page[i] = 0; STATS_INC(b->stats.primErrorPageFree); } @@ -779,13 +778,13 @@ Balloon_ErrorPagesFree(Balloon *b) * Balloon_AllocPage -- * * Attempts to allocate a physical page, inflating balloon "b". - * Informs monitor of PPN for allocated page via backdoor. + * Informs monitor of PPN for allocated page via backdoor. * * Results: * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -854,14 +853,14 @@ Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType) * Balloon_FreePage -- * * Attempts to deallocate a physical page, deflating balloon "b". - * Informs monitor of PPN for deallocated page via backdoor if - * "monitorUnlock" is specified. + * Informs monitor of PPN for deallocated page via backdoor if + * "monitorUnlock" is specified. * * Results: * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -929,15 +928,15 @@ Balloon_FreePage(Balloon *b, int monitorUnlock) * * BalloonDecreaseRateAlloc -- * - * Wrapper to quickly reduce the page allocation rate. This function - * is called only when a CANSLEEP allocation fails. This implies severe - * memory pressure inside the guest, so quickly decrease the rateAlloc. + * Wrapper to quickly reduce the page allocation rate. This function + * is called only when a CANSLEEP allocation fails. This implies severe + * memory pressure inside the guest, so quickly decrease the rateAlloc. * * Results: * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -954,27 +953,27 @@ BalloonDecreaseRateAlloc(Balloon *b) * * BalloonIncreaseRateAlloc -- * - * Wrapper to increase the page allocation rate. + * Wrapper to increase the page allocation rate. * - * This function is called when the balloon target is met or - * b->rateAlloc (or more) pages have been successfully allocated. - * This implies that the guest may not be under high memory - * pressure. So let us increase the rateAlloc. + * This function is called when the balloon target is met or + * b->rateAlloc (or more) pages have been successfully allocated. + * This implies that the guest may not be under high memory + * pressure. So let us increase the rateAlloc. * - * If meeting balloon target requires less than b->rateAlloc - * pages, then we do not change the page allocation rate. + * If meeting balloon target requires less than b->rateAlloc + * pages, then we do not change the page allocation rate. * - * If the number of pages successfully allocated (nAlloc) is far - * higher than b->rateAlloc, then it implies that NOSLEEP - * allocations are highly successful. Therefore, we predict that - * the guest is under no memory pressure, and so increase - * b->rateAlloc quickly. + * If the number of pages successfully allocated (nAlloc) is far + * higher than b->rateAlloc, then it implies that NOSLEEP + * allocations are highly successful. Therefore, we predict that + * the guest is under no memory pressure, and so increase + * b->rateAlloc quickly. * * Results: * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -983,7 +982,7 @@ BalloonIncreaseRateAlloc(Balloon *b, uint32 nAlloc) { if (BALLOON_RATE_ADAPT) { if (nAlloc >= b->rateAlloc) { - uint32 mult = nAlloc / b->rateAlloc; + uint32 mult = nAlloc / b->rateAlloc; b->rateAlloc = MIN(b->rateAlloc + mult * BALLOON_RATE_ALLOC_INC, BALLOON_RATE_ALLOC_MAX); } @@ -1001,7 +1000,7 @@ BalloonIncreaseRateAlloc(Balloon *b, uint32 nAlloc) * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1011,7 +1010,7 @@ BalloonInflate(Balloon *b, uint32 target) int status, allocations = 0; uint32 i, nAllocNoSleep, nAllocCanSleep; - /* + /* * First try NOSLEEP page allocations to inflate balloon. * * If we do not throttle nosleep allocations, we can drain all @@ -1019,10 +1018,10 @@ BalloonInflate(Balloon *b, uint32 target) * As a side-effect, draining free pages helps to inform (force) * the guest to start swapping if balloon target is not met yet, * which is a desired behavior. However, balloon driver can consume - * all available CPU cycles if too many pages are allocated in a - * second. Therefore, we throttle nosleep allocations even when - * the guest is not under memory pressure. OTOH, if we have already - * predicted that the guest is under memory pressure, then we + * all available CPU cycles if too many pages are allocated in a + * second. Therefore, we throttle nosleep allocations even when + * the guest is not under memory pressure. OTOH, if we have already + * predicted that the guest is under memory pressure, then we * slowdown page allocations considerably. */ if (b->slowPageAllocationCycles > 0) { @@ -1036,16 +1035,16 @@ BalloonInflate(Balloon *b, uint32 target) status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_NOSLEEP); if (status != BALLOON_SUCCESS) { if (status != BALLOON_PAGE_ALLOC_FAILURE) { - /* + /* * Not a page allocation failure, so release non-balloonable * pages, and fail. */ Balloon_ErrorPagesFree(b); return(status); } - /* - * NOSLEEP page allocation failed, so the guest is under memory - * pressure. Let us slowdown page allocations for next few + /* + * NOSLEEP page allocation failed, so the guest is under memory + * pressure. Let us slowdown page allocations for next few * cycles so that the guest gets out of memory pressure. */ b->slowPageAllocationCycles = SLOW_PAGE_ALLOCATION_CYCLES; @@ -1053,12 +1052,12 @@ BalloonInflate(Balloon *b, uint32 target) } if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) { - os_yield(); + OS_Yield(); allocations = 0; } } - /* + /* * Check whether nosleep allocation successfully zapped nAllocNoSleep * pages. */ @@ -1068,7 +1067,7 @@ BalloonInflate(Balloon *b, uint32 target) Balloon_ErrorPagesFree(b); return(BALLOON_SUCCESS); } else { - /* + /* * NOSLEEP allocation failed, so the guest is under memory pressure. * If already b->rateAlloc pages were zapped, then succeed. Otherwise, * try CANSLEEP allocation. @@ -1084,14 +1083,14 @@ BalloonInflate(Balloon *b, uint32 target) } } - /* + /* * Use CANSLEEP page allocation to inflate balloon if below target. * * Sleep allocations are required only when nosleep allocation fails. * This implies that the guest is already under memory pressure, so * let us always throttle canSleep allocations. The total number pages - * allocated using noSleep and canSleep methods is throttled at - * b->rateAlloc per second when the guest is under memory pressure. + * allocated using noSleep and canSleep methods is throttled at + * b->rateAlloc per second when the guest is under memory pressure. */ nAllocCanSleep = target - b->nPages; nAllocCanSleep = MIN(nAllocCanSleep, b->rateAlloc - nAllocNoSleep); @@ -1101,7 +1100,7 @@ BalloonInflate(Balloon *b, uint32 target) status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_CANSLEEP); if(status != BALLOON_SUCCESS) { if (status == BALLOON_PAGE_ALLOC_FAILURE) { - /* + /* * CANSLEEP page allocation failed, so guest is under severe * memory pressure. Quickly decrease rateAlloc. */ @@ -1113,17 +1112,17 @@ BalloonInflate(Balloon *b, uint32 target) } if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) { - os_yield(); + OS_Yield(); allocations = 0; } } - /* + /* * Either met the balloon target or b->rateAlloc pages have been * successfully zapped. */ BalloonIncreaseRateAlloc(b, nAllocNoSleep + nAllocCanSleep); - + /* release non-balloonable pages, succeed */ Balloon_ErrorPagesFree(b); return(BALLOON_SUCCESS); @@ -1140,7 +1139,7 @@ BalloonInflate(Balloon *b, uint32 target) * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1149,7 +1148,7 @@ BalloonDeflate(Balloon *b, uint32 target) { int status, i; uint32 nFree = b->nPages - target; - + /* limit deallocation rate */ nFree = MIN(nFree, b->rateFree); @@ -1173,20 +1172,20 @@ BalloonDeflate(Balloon *b, uint32 target) /* everything OK */ return(BALLOON_SUCCESS); } - + /* *---------------------------------------------------------------------- * * Balloon_AdjustSize -- * * Attempts to allocate or deallocate physical pages in order - * to reach desired "target" size for balloon "b". + * to reach desired "target" size for balloon "b". * * Results: * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1224,10 +1223,10 @@ Balloon_AdjustSize(Balloon *b, uint32 target) * Attempts to contact monitor via backdoor to begin operation. * * Results: - * Returns BALLOON_SUCCESS if successful, otherwise error code. + * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1266,10 +1265,10 @@ Balloon_MonitorStart(Balloon *b) * Attempts to contact monitor and report guest OS identity. * * Results: - * Returns BALLOON_SUCCESS if successful, otherwise error code. + * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1311,24 +1310,24 @@ Balloon_MonitorGuestType(Balloon *b) * Balloon_MonitorGetTarget -- * * Attempts to contact monitor via backdoor to obtain desired - * balloon size. + * balloon size. * - * Predicts the maximum achievable balloon size and sends it - * to vmm => vmkernel via vEbx register. + * Predicts the maximum achievable balloon size and sends it + * to vmm => vmkernel via vEbx register. * - * os_predict_max_balloon_pages() returns either predicted max balloon - * pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario, - * vmkernel uses global config options for determining a guest's max - * balloon size. Note that older vmballoon drivers set vEbx to - * BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel - * will fallback to config-based max balloon size estimation. + * OS_PredictMaxReservedPages() returns either predicted max balloon + * pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario, + * vmkernel uses global config options for determining a guest's max + * balloon size. Note that older vmballoon drivers set vEbx to + * BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel + * will fallback to config-based max balloon size estimation. * * Results: - * If successful, sets "target" to value obtained from monitor, + * If successful, sets "target" to value obtained from monitor, * and returns BALLOON_SUCCESS. Otherwise returns error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1340,7 +1339,7 @@ Balloon_MonitorGetTarget(Balloon *b, uint32 *target) /* prepare backdoor args */ bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_TARGET; - bp.in.size = os_predict_max_balloon_pages(); + bp.in.size = OS_PredictMaxReservedPages(); /* invoke backdoor */ Backdoor_Balloon(&bp); @@ -1369,14 +1368,14 @@ Balloon_MonitorGetTarget(Balloon *b, uint32 *target) * * Balloon_MonitorLockPage -- * - * Attempts to contact monitor and add PPN containing "addr" - * to set of "balloon locked" pages. + * Attempts to contact monitor and add PPN containing "addr" + * to set of "balloon locked" pages. * * Results: - * Returns BALLOON_SUCCESS if successful, otherwise error code. + * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1428,14 +1427,14 @@ Balloon_MonitorLockPage(Balloon *b, unsigned long addr) * * Balloon_MonitorUnlockPage -- * - * Attempts to contact monitor and remove PPN containing "addr" - * from set of "balloon locked" pages. + * Attempts to contact monitor and remove PPN containing "addr" + * from set of "balloon locked" pages. * * Results: - * Returns BALLOON_SUCCESS if successful, otherwise error code. + * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1497,18 +1496,18 @@ BalloonModuleInit(void) return(BALLOON_FAILURE); } + /* os-specific initialization */ + OS_Init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead); + /* initialize global state */ Balloon_Init(b); - /* os-specific initialization */ - os_init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead); - os_timer_init(Balloon_BH, (void *) b, os_timer_hz()); - /* start timer */ + OS_TimerInit(BalloonTimerHandler, b, OS_TimerHz()); Balloon_StartTimer(b); /* everything OK */ - return(BALLOON_SUCCESS); + return BALLOON_SUCCESS; } static void @@ -1528,8 +1527,8 @@ BalloonModuleCleanup(void) Balloon_Deallocate(b); /* os-specific cleanup */ - os_cleanup(); -} + OS_Cleanup(); +} int init_module(void) { diff --git a/open-vm-tools/modules/linux/dkms.conf b/open-vm-tools/modules/linux/dkms.conf index 664dc479e..d35b0df41 100644 --- a/open-vm-tools/modules/linux/dkms.conf +++ b/open-vm-tools/modules/linux/dkms.conf @@ -1,5 +1,5 @@ PACKAGE_NAME=open-vm-tools -PACKAGE_VERSION=2009.07.22 +PACKAGE_VERSION=2009.08.24 MAKE_CMD_TMPL="make VM_UNAME=\$kernelver \ MODULEBUILDDIR=$dkms_tree/$PACKAGE_NAME/$PACKAGE_VERSION/build" diff --git a/open-vm-tools/modules/linux/dkms.sh b/open-vm-tools/modules/linux/dkms.sh index 4513e8e8b..a85ae7d3f 100644 --- a/open-vm-tools/modules/linux/dkms.sh +++ b/open-vm-tools/modules/linux/dkms.sh @@ -28,16 +28,17 @@ then echo " src: root of unpacked open-vm-tools package" echo " dst: where to create the dkms tree" echo - echo "The script will create an 'open-vm-tools' module with version 2009.07.22." + echo "The script will create an 'open-vm-tools' module with version 2009.08.24." exit 1 fi src=$1 -dst=$2/open-vm-tools-2009.07.22 +dst=$2/open-vm-tools-2009.08.24 SHARED_HEADERS="backdoor_def.h" SHARED_HEADERS="$SHARED_HEADERS backdoor_types.h" SHARED_HEADERS="$SHARED_HEADERS circList.h" +SHARED_HEADERS="$SHARED_HEADERS community_source.h" SHARED_HEADERS="$SHARED_HEADERS dbllnklst.h" SHARED_HEADERS="$SHARED_HEADERS guest_msg_def.h" SHARED_HEADERS="$SHARED_HEADERS includeCheck.h" diff --git a/open-vm-tools/modules/linux/pvscsi/pvscsi.c b/open-vm-tools/modules/linux/pvscsi/pvscsi.c index d5144a849..125b5cc88 100644 --- a/open-vm-tools/modules/linux/pvscsi/pvscsi.c +++ b/open-vm-tools/modules/linux/pvscsi/pvscsi.c @@ -454,11 +454,11 @@ static int __devinit pvscsi_probe(struct pci_dev *pdev, if (pdev->vendor != PCI_VENDOR_ID_VMWARE) goto out_disable_device; - if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0 && - pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) == 0) { + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0 && + pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) { printk(KERN_INFO "pvscsi: using 64bit dma\n"); - } else if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) == 0 && - pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK) == 0) { + } else if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) == 0 && + pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)) == 0) { printk(KERN_INFO "pvscsi: using 32bit dma\n"); } else { printk(KERN_ERR "pvscsi: failed to set DMA mask\n"); diff --git a/open-vm-tools/modules/linux/pvscsi/scsi_defs.h b/open-vm-tools/modules/linux/pvscsi/scsi_defs.h index 642f01340..855f67d00 100644 --- a/open-vm-tools/modules/linux/pvscsi/scsi_defs.h +++ b/open-vm-tools/modules/linux/pvscsi/scsi_defs.h @@ -36,6 +36,7 @@ #include "vm_basic_defs.h" // for offsetof() +#define SCSI_MIN_CMD_LEN 6 #define SCSI_MAX_CMD_LEN 16 /* @@ -47,160 +48,160 @@ * NB: Command descriptions come from the "SCSI Book" and not * from the SCSI specifications (YMMV). */ -#define SCSI_CMD_TEST_UNIT_READY 0x00 // test if LUN ready to accept a command -#define SCSI_CMD_REZERO_UNIT 0x01 // seek to track 0 -#define SCSI_CMD_REQUEST_SENSE 0x03 // return detailed error information -#define SCSI_CMD_FORMAT_UNIT 0x04 // -#define SCSI_CMD_READ_BLOCKLIMITS 0x05 // -#define SCSI_CMD_REASSIGN_BLOCKS 0x07 // -#define SCSI_CMD_INIT_ELEMENT_STATUS 0x07 // Media changer -#define SCSI_CMD_READ6 0x08 // read w/ limited addressing -#define SCSI_CMD_WRITE6 0x0a // write w/ limited addressing -#define SCSI_CMD_PRINT 0x0a // print data -#define SCSI_CMD_SEEK6 0x0b // seek to LBN -#define SCSI_CMD_SLEW_AND_PRINT 0x0b // advance and print -#define SCSI_CMD_READ_REVERSE 0x0f // read backwards -#define SCSI_CMD_WRITE_FILEMARKS 0x10 // -#define SCSI_CMD_SYNC_BUFFER 0x10 // print contents of buffer -#define SCSI_CMD_SPACE 0x11 // -#define SCSI_CMD_INQUIRY 0x12 // return LUN-specific information -#define SCSI_CMD_RECOVER_BUFFERED 0x14 // recover buffered data -#define SCSI_CMD_MODE_SELECT 0x15 // set device parameters -#define SCSI_CMD_RESERVE_UNIT 0x16 // make LUN accessible only to certain initiators -#define SCSI_CMD_RELEASE_UNIT 0x17 // make LUN accessible to other initiators -#define SCSI_CMD_COPY 0x18 // autonomous copy from/to another device -#define SCSI_CMD_ERASE 0x19 // -#define SCSI_CMD_MODE_SENSE 0x1a // read device parameters -#define SCSI_CMD_START_UNIT 0x1b // load/unload medium -#define SCSI_CMD_SCAN 0x1b // perform scan -#define SCSI_CMD_STOP_PRINT 0x1b // interrupt printing -#define SCSI_CMD_RECV_DIAGNOSTIC 0x1c // read self-test results -#define SCSI_CMD_SEND_DIAGNOSTIC 0x1d // initiate self-test -#define SCSI_CMD_MEDIUM_REMOVAL 0x1e // lock/unlock door -#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23 // read format capacities -#define SCSI_CMD_SET_WINDOW 0x24 // set scanning window -#define SCSI_CMD_GET_WINDOW 0x25 // get scanning window -#define SCSI_CMD_READ_CAPACITY 0x25 // read number of logical blocks -#define SCSI_CMD_READ10 0x28 // read -#define SCSI_CMD_READ_GENERATION 0x29 // read max generation address of LBN -#define SCSI_CMD_WRITE10 0x2a // write -#define SCSI_CMD_SEEK10 0x2b // seek LBN -#define SCSI_CMD_POSITION_TO_ELEMENT 0x2b // media changer -#define SCSI_CMD_ERASE10 0x2c -#define SCSI_CMD_READ_UPDATED_BLOCK 0x2d // read specific version of changed block -#define SCSI_CMD_WRITE_VERIFY 0x2e // write w/ verify of success -#define SCSI_CMD_VERIFY 0x2f // verify success -#define SCSI_CMD_SEARCH_DATA_HIGH 0x30 // search for data pattern -#define SCSI_CMD_SEARCH_DATA_EQUAL 0x31 // search for data pattern -#define SCSI_CMD_SEARCH_DATA_LOW 0x32 // search for data pattern -#define SCSI_CMD_SET_LIMITS 0x33 // define logical block boundaries -#define SCSI_CMD_PREFETCH 0x34 // read data into buffer -#define SCSI_CMD_READ_POSITION 0x34 // read current tape position -#define SCSI_CMD_SYNC_CACHE 0x35 // re-read data into buffer -#define SCSI_CMD_LOCKUNLOCK_CACHE 0x36 // lock/unlock data in cache -#define SCSI_CMD_READ_DEFECT_DATA 0x37 // -#define SCSI_CMD_MEDIUM_SCAN 0x38 // search for free area -#define SCSI_CMD_COMPARE 0x39 // compare data -#define SCSI_CMD_COPY_VERIFY 0x3a // autonomous copy w/ verify -#define SCSI_CMD_WRITE_BUFFER 0x3b // write data buffer -#define SCSI_CMD_READ_BUFFER 0x3c // read data buffer -#define SCSI_CMD_UPDATE_BLOCK 0x3d // substitute block with an updated one -#define SCSI_CMD_READ_LONG 0x3e // read data and ECC -#define SCSI_CMD_WRITE_LONG 0x3f // write data and ECC -#define SCSI_CMD_CHANGE_DEF 0x40 // set SCSI version -#define SCSI_CMD_WRITE_SAME 0x41 // -#define SCSI_CMD_READ_SUBCHANNEL 0x42 // read subchannel data and status -#define SCSI_CMD_READ_TOC 0x43 // read contents table -#define SCSI_CMD_READ_HEADER 0x44 // read LBN header -#define SCSI_CMD_PLAY_AUDIO10 0x45 // audio playback -#define SCSI_CMD_GET_CONFIGURATION 0x46 // get configuration (SCSI-3) -#define SCSI_CMD_PLAY_AUDIO_MSF 0x47 // audio playback starting at MSF address -#define SCSI_CMD_PLAY_AUDIO_TRACK 0x48 // audio playback starting at track/index -#define SCSI_CMD_PLAY_AUDIO_RELATIVE 0x49 // audio playback starting at relative track -#define SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION 0x4a -#define SCSI_CMD_PAUSE 0x4b // audio playback pause/resume -#define SCSI_CMD_LOG_SELECT 0x4c // select statistics -#define SCSI_CMD_LOG_SENSE 0x4d // read statistics -#define SCSI_CMD_STOP_PLAY 0x4e // audio playback stop -#define SCSI_CMD_READ_DISC_INFO 0x51 // info on CDRs -#define SCSI_CMD_READ_TRACK_INFO 0x52 // track info on CDRs -#define SCSI_CMD_RESERVE_TRACK 0x53 // leave space for data on CDRs -#define SCSI_CMD_SEND_OPC_INFORMATION 0x54 // Optimum Power Calibration -#define SCSI_CMD_MODE_SELECT10 0x55 // set device parameters -#define SCSI_CMD_RESERVE_UNIT10 0x56 // -#define SCSI_CMD_RELEASE_UNIT10 0x57 // -#define SCSI_CMD_REPAIR_TRACK 0x58 -#define SCSI_CMD_MODE_SENSE10 0x5a // read device parameters -#define SCSI_CMD_CLOSE_SESSION 0x5b // close area/sesssion (recordable) -#define SCSI_CMD_READ_BUFFER_CAPACITY 0x5c // CDR burning info. -#define SCSI_CMD_SEND_CUE_SHEET 0x5d // (CDR Related?) -#define SCSI_CMD_PERSISTENT_RESERVE_IN 0x5e // -#define SCSI_CMD_PERSISTENT_RESERVE_OUT 0x5f // -#define SCSI_CMD_XDWRITE_EXTENDED 0x80 -#define SCSI_CMD_REBUILD 0x81 -#define SCSI_CMD_REGENERATE 0x82 -#define SCSI_CMD_EXTENDED_COPY 0x83 // extended copy -#define SCSI_CMD_RECEIVE_COPY_RESULTS 0x84 // receive copy results -#define SCSI_CMD_READ16 0x88 // read data -#define SCSI_CMD_WRITE16 0x8a // write data -#define SCSI_CMD_ORWRITE16 0x8b -#define SCSI_CMD_READ_ATTRIBUTE 0x8c // read attribute -#define SCSI_CMD_WRITE_ATTRIBUTE 0x8d // write attribute -#define SCSI_CMD_WRITE_VERIFY16 0x8e -#define SCSI_CMD_VERIFY16 0x8f -#define SCSI_CMD_PREFETCH16 0x90 -#define SCSI_CMD_SYNC_CACHE16 0x91 -#define SCSI_CMD_WRITE_SAME16 0x93 -#define SCSI_CMD_READ_CAPACITY16 0x9e // read number of logical blocks -#define SCSI_CMD_WRITE_LONG16 0x9f -#define SCSI_CMD_REPORT_LUNS 0xa0 // -#define SCSI_CMD_BLANK 0xa1 // erase RW media -#define SCSI_CMD_SECURITY_PROTOCOL_IN 0xa2 // -#define SCSI_CMD_MAINTENANCE_IN 0xa3 // service actions define reports -#define SCSI_CMD_MAINTENANCE_OUT 0xa4 // service actions define changes -#define SCSI_CMD_SEND_KEY 0xa3 -#define SCSI_CMD_REPORT_KEY 0xa4 // report key (SCSI-3) -#define SCSI_CMD_MOVE_MEDIUM 0xa5 // -#define SCSI_CMD_PLAY_AUDIO12 0xa5 // audio playback -#define SCSI_CMD_EXCHANGE_MEDIUM 0xa6 // -#define SCSI_CMD_LOADCD 0xa6 // -#define SCSI_CMD_SET_READ_AHEAD 0xa7 -#define SCSI_CMD_READ12 0xa8 // read (SCSI-3) -#define SCSI_CMD_PLAY_TRACK_RELATIVE 0xa9 // audio playback starting at relative track -#define SCSI_CMD_WRITE12 0xaa // write data -#define SCSI_CMD_READ_MEDIA_SERIAL_NUMBER 0xab // -#define SCSI_CMD_ERASE12 0xac // erase logical block -#define SCSI_CMD_GET_PERFORMANCE 0xac // -#define SCSI_CMD_READ_DVD_STRUCTURE 0xad // read DVD structure (SCSI-3) -#define SCSI_CMD_WRITE_VERIFY12 0xae // write logical block, verify success -#define SCSI_CMD_VERIFY12 0xaf // verify data -#define SCSI_CMD_SEARCH_DATA_HIGH12 0xb0 // search data pattern -#define SCSI_CMD_SEARCH_DATA_EQUAL12 0xb1 // search data pattern -#define SCSI_CMD_SEARCH_DATA_LOW12 0xb2 // search data pattern -#define SCSI_CMD_SET_LIMITS12 0xb3 // set block limits +#define SCSI_CMD_TEST_UNIT_READY 0x00 // test if LUN ready to accept a command +#define SCSI_CMD_REZERO_UNIT 0x01 // seek to track 0 +#define SCSI_CMD_REQUEST_SENSE 0x03 // return detailed error information +#define SCSI_CMD_FORMAT_UNIT 0x04 // +#define SCSI_CMD_READ_BLOCKLIMITS 0x05 // +#define SCSI_CMD_REASSIGN_BLOCKS 0x07 // +#define SCSI_CMD_INIT_ELEMENT_STATUS 0x07 // Media changer +#define SCSI_CMD_READ6 0x08 // read w/ limited addressing +#define SCSI_CMD_WRITE6 0x0a // write w/ limited addressing +#define SCSI_CMD_PRINT 0x0a // print data +#define SCSI_CMD_SEEK6 0x0b // seek to LBN +#define SCSI_CMD_SLEW_AND_PRINT 0x0b // advance and print +#define SCSI_CMD_READ_REVERSE 0x0f // read backwards +#define SCSI_CMD_WRITE_FILEMARKS 0x10 // +#define SCSI_CMD_SYNC_BUFFER 0x10 // print contents of buffer +#define SCSI_CMD_SPACE 0x11 // +#define SCSI_CMD_INQUIRY 0x12 // return LUN-specific information +#define SCSI_CMD_RECOVER_BUFFERED 0x14 // recover buffered data +#define SCSI_CMD_MODE_SELECT 0x15 // set device parameters +#define SCSI_CMD_RESERVE_UNIT 0x16 // make LUN accessible only to certain initiators +#define SCSI_CMD_RELEASE_UNIT 0x17 // make LUN accessible to other initiators +#define SCSI_CMD_COPY 0x18 // autonomous copy from/to another device +#define SCSI_CMD_ERASE 0x19 // +#define SCSI_CMD_MODE_SENSE 0x1a // read device parameters +#define SCSI_CMD_START_UNIT 0x1b // load/unload medium +#define SCSI_CMD_SCAN 0x1b // perform scan +#define SCSI_CMD_STOP_PRINT 0x1b // interrupt printing +#define SCSI_CMD_RECV_DIAGNOSTIC 0x1c // read self-test results +#define SCSI_CMD_SEND_DIAGNOSTIC 0x1d // initiate self-test +#define SCSI_CMD_MEDIUM_REMOVAL 0x1e // lock/unlock door +#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23 // read format capacities +#define SCSI_CMD_SET_WINDOW 0x24 // set scanning window +#define SCSI_CMD_GET_WINDOW 0x25 // get scanning window +#define SCSI_CMD_READ_CAPACITY 0x25 // read number of logical blocks +#define SCSI_CMD_READ10 0x28 // read +#define SCSI_CMD_READ_GENERATION 0x29 // read max generation address of LBN +#define SCSI_CMD_WRITE10 0x2a // write +#define SCSI_CMD_SEEK10 0x2b // seek LBN +#define SCSI_CMD_POSITION_TO_ELEMENT 0x2b // media changer +#define SCSI_CMD_ERASE10 0x2c // +#define SCSI_CMD_READ_UPDATED_BLOCK 0x2d // read specific version of changed block +#define SCSI_CMD_WRITE_VERIFY 0x2e // write w/ verify of success +#define SCSI_CMD_VERIFY 0x2f // verify success +#define SCSI_CMD_SEARCH_DATA_HIGH 0x30 // search for data pattern +#define SCSI_CMD_SEARCH_DATA_EQUAL 0x31 // search for data pattern +#define SCSI_CMD_SEARCH_DATA_LOW 0x32 // search for data pattern +#define SCSI_CMD_SET_LIMITS 0x33 // define logical block boundaries +#define SCSI_CMD_PREFETCH 0x34 // read data into buffer +#define SCSI_CMD_READ_POSITION 0x34 // read current tape position +#define SCSI_CMD_SYNC_CACHE 0x35 // re-read data into buffer +#define SCSI_CMD_LOCKUNLOCK_CACHE 0x36 // lock/unlock data in cache +#define SCSI_CMD_READ_DEFECT_DATA 0x37 // +#define SCSI_CMD_MEDIUM_SCAN 0x38 // search for free area +#define SCSI_CMD_COMPARE 0x39 // compare data +#define SCSI_CMD_COPY_VERIFY 0x3a // autonomous copy w/ verify +#define SCSI_CMD_WRITE_BUFFER 0x3b // write data buffer +#define SCSI_CMD_READ_BUFFER 0x3c // read data buffer +#define SCSI_CMD_UPDATE_BLOCK 0x3d // substitute block with an updated one +#define SCSI_CMD_READ_LONG 0x3e // read data and ECC +#define SCSI_CMD_WRITE_LONG 0x3f // write data and ECC +#define SCSI_CMD_CHANGE_DEF 0x40 // set SCSI version +#define SCSI_CMD_WRITE_SAME 0x41 // +#define SCSI_CMD_READ_SUBCHANNEL 0x42 // read subchannel data and status +#define SCSI_CMD_READ_TOC 0x43 // read contents table +#define SCSI_CMD_READ_HEADER 0x44 // read LBN header +#define SCSI_CMD_PLAY_AUDIO10 0x45 // audio playback +#define SCSI_CMD_GET_CONFIGURATION 0x46 // get configuration (SCSI-3) +#define SCSI_CMD_PLAY_AUDIO_MSF 0x47 // audio playback starting at MSF address +#define SCSI_CMD_PLAY_AUDIO_TRACK 0x48 // audio playback starting at track/index +#define SCSI_CMD_PLAY_AUDIO_RELATIVE 0x49 // audio playback starting at relative track +#define SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION 0x4a // +#define SCSI_CMD_PAUSE 0x4b // audio playback pause/resume +#define SCSI_CMD_LOG_SELECT 0x4c // select statistics +#define SCSI_CMD_LOG_SENSE 0x4d // read statistics +#define SCSI_CMD_STOP_PLAY 0x4e // audio playback stop +#define SCSI_CMD_READ_DISC_INFO 0x51 // info on CDRs +#define SCSI_CMD_READ_TRACK_INFO 0x52 // track info on CDRs +#define SCSI_CMD_RESERVE_TRACK 0x53 // leave space for data on CDRs +#define SCSI_CMD_SEND_OPC_INFORMATION 0x54 // Optimum Power Calibration +#define SCSI_CMD_MODE_SELECT10 0x55 // set device parameters +#define SCSI_CMD_RESERVE_UNIT10 0x56 // +#define SCSI_CMD_RELEASE_UNIT10 0x57 // +#define SCSI_CMD_REPAIR_TRACK 0x58 // +#define SCSI_CMD_MODE_SENSE10 0x5a // read device parameters +#define SCSI_CMD_CLOSE_SESSION 0x5b // close area/sesssion (recordable) +#define SCSI_CMD_READ_BUFFER_CAPACITY 0x5c // CDR burning info. +#define SCSI_CMD_SEND_CUE_SHEET 0x5d // (CDR Related?) +#define SCSI_CMD_PERSISTENT_RESERVE_IN 0x5e // +#define SCSI_CMD_PERSISTENT_RESERVE_OUT 0x5f // +#define SCSI_CMD_XDWRITE_EXTENDED 0x80 // +#define SCSI_CMD_REBUILD 0x81 // +#define SCSI_CMD_REGENERATE 0x82 // +#define SCSI_CMD_EXTENDED_COPY 0x83 // extended copy +#define SCSI_CMD_RECEIVE_COPY_RESULTS 0x84 // receive copy results +#define SCSI_CMD_READ16 0x88 // read data +#define SCSI_CMD_WRITE16 0x8a // write data +#define SCSI_CMD_ORWRITE16 0x8b // +#define SCSI_CMD_READ_ATTRIBUTE 0x8c // read attribute +#define SCSI_CMD_WRITE_ATTRIBUTE 0x8d // write attribute +#define SCSI_CMD_WRITE_VERIFY16 0x8e // +#define SCSI_CMD_VERIFY16 0x8f // +#define SCSI_CMD_PREFETCH16 0x90 // +#define SCSI_CMD_SYNC_CACHE16 0x91 // +#define SCSI_CMD_WRITE_SAME16 0x93 // +#define SCSI_CMD_READ_CAPACITY16 0x9e // read number of logical blocks +#define SCSI_CMD_WRITE_LONG16 0x9f // +#define SCSI_CMD_REPORT_LUNS 0xa0 // +#define SCSI_CMD_BLANK 0xa1 // erase RW media +#define SCSI_CMD_SECURITY_PROTOCOL_IN 0xa2 // +#define SCSI_CMD_MAINTENANCE_IN 0xa3 // service actions define reports +#define SCSI_CMD_MAINTENANCE_OUT 0xa4 // service actions define changes +#define SCSI_CMD_SEND_KEY 0xa3 // +#define SCSI_CMD_REPORT_KEY 0xa4 // report key (SCSI-3) +#define SCSI_CMD_MOVE_MEDIUM 0xa5 // +#define SCSI_CMD_PLAY_AUDIO12 0xa5 // audio playback +#define SCSI_CMD_EXCHANGE_MEDIUM 0xa6 // +#define SCSI_CMD_LOADCD 0xa6 // +#define SCSI_CMD_SET_READ_AHEAD 0xa7 // +#define SCSI_CMD_READ12 0xa8 // read (SCSI-3) +#define SCSI_CMD_PLAY_TRACK_RELATIVE 0xa9 // audio playback starting at relative track +#define SCSI_CMD_WRITE12 0xaa // write data +#define SCSI_CMD_READ_MEDIA_SERIAL_NUMBER 0xab // +#define SCSI_CMD_ERASE12 0xac // erase logical block +#define SCSI_CMD_GET_PERFORMANCE 0xac // +#define SCSI_CMD_READ_DVD_STRUCTURE 0xad // read DVD structure (SCSI-3) +#define SCSI_CMD_WRITE_VERIFY12 0xae // write logical block, verify success +#define SCSI_CMD_VERIFY12 0xaf // verify data +#define SCSI_CMD_SEARCH_DATA_HIGH12 0xb0 // search data pattern +#define SCSI_CMD_SEARCH_DATA_EQUAL12 0xb1 // search data pattern +#define SCSI_CMD_SEARCH_DATA_LOW12 0xb2 // search data pattern +#define SCSI_CMD_SET_LIMITS12 0xb3 // set block limits #define SCSI_CMD_REQUEST_VOLUME_ELEMENT_ADDR 0xb5 // -#define SCSI_CMD_SECURITY_PROTOCOL_OUT 0xb5 -#define SCSI_CMD_SEND_VOLUME_TAG 0xb6 // -#define SCSI_CMD_SET_STREAMING 0xb6 // For avoiding over/underrun -#define SCSI_CMD_READ_DEFECT_DATA12 0xb7 // read defect data information -#define SCSI_CMD_READ_ELEMENT_STATUS 0xb8 // read element status -#define SCSI_CMD_SELECT_CDROM_SPEED 0xb8 // set data rate -#define SCSI_CMD_READ_CD_MSF 0xb9 // read CD information (all formats, MSF addresses) -#define SCSI_CMD_AUDIO_SCAN 0xba // fast audio playback -#define SCSI_CMD_SET_CDROM_SPEED 0xbb // (proposed) -#define SCSI_CMD_SEND_CDROM_XA_DATA 0xbc -#define SCSI_CMD_PLAY_CD 0xbc -#define SCSI_CMD_MECH_STATUS 0xbd -#define SCSI_CMD_READ_CD 0xbe // read CD information (all formats, MSF addresses) -#define SCSI_CMD_SEND_DVD_STRUCTURE 0xbf // burning DVDs? +#define SCSI_CMD_SECURITY_PROTOCOL_OUT 0xb5 // +#define SCSI_CMD_SEND_VOLUME_TAG 0xb6 // +#define SCSI_CMD_SET_STREAMING 0xb6 // For avoiding over/underrun +#define SCSI_CMD_READ_DEFECT_DATA12 0xb7 // read defect data information +#define SCSI_CMD_READ_ELEMENT_STATUS 0xb8 // read element status +#define SCSI_CMD_SELECT_CDROM_SPEED 0xb8 // set data rate +#define SCSI_CMD_READ_CD_MSF 0xb9 // read CD information (all formats, MSF addresses) +#define SCSI_CMD_AUDIO_SCAN 0xba // fast audio playback +#define SCSI_CMD_SET_CDROM_SPEED 0xbb // (proposed) +#define SCSI_CMD_SEND_CDROM_XA_DATA 0xbc // +#define SCSI_CMD_PLAY_CD 0xbc // +#define SCSI_CMD_MECH_STATUS 0xbd // +#define SCSI_CMD_READ_CD 0xbe // read CD information (all formats, MSF addresses) +#define SCSI_CMD_SEND_DVD_STRUCTURE 0xbf // burning DVDs? /* - * A workaround for a specific scanner (NIKON LS-2000). + * A workaround for a specific scanner (NIKON LS-2000). * Can be removed once Linux backend uses 2.4.x interface */ #define SCSI_CMD_VENDOR_NIKON_UNKNOWN 0xe1 -#define SCSI_SENSE_KEY_NONE 0x0 // there is no sense information +#define SCSI_SENSE_KEY_NONE 0x0 // there is no sense information #define SCSI_SENSE_KEY_RECOVERED_ERROR 0x1 // the last command completed succesfully but used error correction in the process #define SCSI_SENSE_KEY_NOT_READY 0x2 // the addressed LUN is not ready to be accessed #define SCSI_SENSE_KEY_MEDIUM_ERROR 0x3 // the target detected a data error on the medium @@ -212,60 +213,60 @@ #define SCSI_SENSE_KEY_VENDOR_SPECIFIC 0x9 // report vendor specific condition #define SCSI_SENSE_KEY_COPY_ABORTED 0xa // COPY, COMPARE, or COPY AND VERIFY was aborted #define SCSI_SENSE_KEY_ABORTED_CMD 0xb // the target aborted the command -#define SCSI_SENSE_KEY_EQUAL 0xc // comparison for SEARCH DATA was unsuccessful +#define SCSI_SENSE_KEY_EQUAL 0xc // comparison for SEARCH DATA was unsuccessful #define SCSI_SENSE_KEY_VOLUME_OVERFLOW 0xd // the medium is full #define SCSI_SENSE_KEY_MISCOMPARE 0xe // source and data on the medium do not agree /* - * The Additional Sense Code - ASC and - * Additional Sense Code Qualifiers - ASCQ - * always come in pairs. + * The Additional Sense Code - ASC + * and Additional Sense Code Qualifiers - ASCQ + * always come in pairs. * * Note: * These values are found at senseBuffer[12} and senseBuffer[13]. * You may see references to these in legacy code. New code should make an * attempt to use the ASC/ASCQ syntax. */ -#define SCSI_ASC_LU_NOT_READY 0x04 // logical unit not ready -#define SCSI_ASC_LU_NOT_READY_ASCQ_UNIT_BECOMING_READY 0x01 -#define SCSI_ASC_LU_NOT_READY_ASCQ_INIT_CMD_REQUIRED 0x02 // initializing command required -#define SCSI_ASC_LU_NOT_READY_ASCQ_MANUAL_INTERVENTION_REQUIRED 0x03 -#define SCSI_ASC_LU_NOT_READY_ASCQ_TARGET_PORT_IN_TRANSITION 0x0a // an ascq -#define SCSI_ASC_LU_NOT_READY_ASCQ_TARGET_PORT_IN_STANDBY_MODE 0x0b // an ascq -#define SCSI_ASC_LU_NO_RESPONSE_TO_SELECTION 0x05 // logical unit doesn't respond to selection -#define SCSI_ASC_NO_REFERENCE_POSITION_FOUND 0x06 -#define SCSI_ASC_WRITE_ERROR 0x0c // Write error -#define SCSI_ASC_UNRECOVERED_READ_ERROR 0x11 // Unrecovered read error -#define SCSI_ASC_PARAM_LIST_LENGTH_ERROR 0x1a // parameter list length error -#define SCSI_ASC_RECOVERED_DATA 0x17 -#define SCSI_ASC_INVALID_COMMAND_OPERATION 0x20 // invalid command operation code -#define SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 // Invalid LBA -#define SCSI_ASC_INVALID_FIELD_IN_CDB 0x24 -#define SCSI_ASC_LU_NOT_SUPPORTED 0x25 // LU has been removed -#define SCSI_ASC_INVALID_FIELD_IN_PARAMETER_LIST 0x26 -#define SCSI_ASC_WRITE_PROTECTED 0x27 // device is write protected -#define SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 // after changing medium -#define SCSI_ASC_POWER_ON_OR_RESET 0x29 // device power-on or SCSI reset -#define SCSI_ASC_ASYMMETRIC_ACCESS_STATE_CHANGED 0x2a -#define SCSI_ASC_INCOMPATIBLE_MEDIUM 0x30 // Generic bad medium error -#define SCSI_ASC_SAVING_PARAMS_NOT_SUPPORTED 0x39 // Saving parameters not supported -#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3a // changing medium -#define SCSI_ASC_MEDIUM_NOT_PRESENT_ASCQ_TRAY_OPEN 0x02 // an ascq -#define SCSI_ASC_INVALID_MESSAGE_ERROR 0x49 -#define SCSI_ASC_COMMAND_PHASE_ERROR 0x4a -#define SCSI_ASC_DATA_PHASE_ERROR 0x4b -#define SCSI_ASC_MEDIUM_REMOVAL_FAILED 0x53 // w/ 0x4 it is failed, 0x5 is prevented -#define SCSI_ASC_INSUFFICIENT_REGISTRATION_RESOURCES 0x55 // during persistent reservations -#define SCSI_ASCQ_INSUFFICIENT_REGISTRATION_RESOURCES 0x04 -#define SCSI_ASCQ_ASYMMETRIC_ACCESS_STATE_CHANGED 0x06 -#define SCSI_ASCQ_TARGET_PORT_IN_STANDBY_STATE 0x0b -#define SCSI_ASCQ_TARGET_PORT_IN_UNAVAILABLE_STATE 0x0c -#define SCSI_ASC_INVALID_MODE_FOR_THIS_TRACK 0x64 - -#define SCSI_TAG_ENABLE 0x20 // Set to indicate tag is valid -#define SCSI_TAG_SIMPLE (SCSI_TAG_ENABLE|0x0) // No constraint -#define SCSI_TAG_HEAD (SCSI_TAG_ENABLE|0x1) // Always first -#define SCSI_TAG_ORDER (SCSI_TAG_ENABLE|0x2) // Syncronizing +#define SCSI_ASC_LU_NOT_READY 0x04 // logical unit not ready +#define SCSI_ASC_LU_NOT_READY_ASCQ_UNIT_BECOMING_READY 0x01 +#define SCSI_ASC_LU_NOT_READY_ASCQ_INIT_CMD_REQUIRED 0x02 // initializing command required +#define SCSI_ASC_LU_NOT_READY_ASCQ_MANUAL_INTERVENTION_REQUIRED 0x03 +#define SCSI_ASC_LU_NOT_READY_ASCQ_TARGET_PORT_IN_TRANSITION 0x0a // an ascq +#define SCSI_ASC_LU_NOT_READY_ASCQ_TARGET_PORT_IN_STANDBY_MODE 0x0b // an ascq +#define SCSI_ASC_LU_NO_RESPONSE_TO_SELECTION 0x05 // logical unit doesn't respond to selection +#define SCSI_ASC_NO_REFERENCE_POSITION_FOUND 0x06 +#define SCSI_ASC_WRITE_ERROR 0x0c // Write error +#define SCSI_ASC_UNRECOVERED_READ_ERROR 0x11 // Unrecovered read error +#define SCSI_ASC_PARAM_LIST_LENGTH_ERROR 0x1a // parameter list length error +#define SCSI_ASC_RECOVERED_DATA 0x17 +#define SCSI_ASC_INVALID_COMMAND_OPERATION 0x20 // invalid command operation code +#define SCSI_ASC_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE 0x21 // Invalid LBA +#define SCSI_ASC_INVALID_FIELD_IN_CDB 0x24 +#define SCSI_ASC_LU_NOT_SUPPORTED 0x25 // LU has been removed +#define SCSI_ASC_INVALID_FIELD_IN_PARAMETER_LIST 0x26 +#define SCSI_ASC_WRITE_PROTECTED 0x27 // device is write protected +#define SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 // after changing medium +#define SCSI_ASC_POWER_ON_OR_RESET 0x29 // device power-on or SCSI reset +#define SCSI_ASC_ASYMMETRIC_ACCESS_STATE_CHANGED 0x2a +#define SCSI_ASC_INCOMPATIBLE_MEDIUM 0x30 // Generic bad medium error +#define SCSI_ASC_SAVING_PARAMS_NOT_SUPPORTED 0x39 // Saving parameters not supported +#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3a // changing medium +#define SCSI_ASC_MEDIUM_NOT_PRESENT_ASCQ_TRAY_OPEN 0x02 // an ascq +#define SCSI_ASC_INVALID_MESSAGE_ERROR 0x49 +#define SCSI_ASC_COMMAND_PHASE_ERROR 0x4a +#define SCSI_ASC_DATA_PHASE_ERROR 0x4b +#define SCSI_ASC_MEDIUM_REMOVAL_FAILED 0x53 // w/ 0x4 it is failed, 0x5 is prevented +#define SCSI_ASC_INSUFFICIENT_REGISTRATION_RESOURCES 0x55 // during persistent reservations +#define SCSI_ASCQ_INSUFFICIENT_REGISTRATION_RESOURCES 0x04 +#define SCSI_ASCQ_ASYMMETRIC_ACCESS_STATE_CHANGED 0x06 +#define SCSI_ASCQ_TARGET_PORT_IN_STANDBY_STATE 0x0b +#define SCSI_ASCQ_TARGET_PORT_IN_UNAVAILABLE_STATE 0x0c +#define SCSI_ASC_INVALID_MODE_FOR_THIS_TRACK 0x64 + +#define SCSI_TAG_ENABLE 0x20 // Set to indicate tag is valid +#define SCSI_TAG_SIMPLE (SCSI_TAG_ENABLE|0x0) // No constraint +#define SCSI_TAG_HEAD (SCSI_TAG_ENABLE|0x1) // Always first +#define SCSI_TAG_ORDER (SCSI_TAG_ENABLE|0x2) // Syncronizing #define SCSI_CMD_START_UNIT_START_BIT 0x01 // Value of Start bit for SCSI_CMD_START_UNIT @@ -284,22 +285,23 @@ * We do not support 16-byte CDB's, only 6-, 10-, and 12-byte versions. */ typedef struct { - uint32 opcode:8, // operation code - lun:3, // logical unit number - lbn:21; // logical block number - uint8 len; // data length - uint8 ctrl; // control byte + uint8 opcode; // operation code + uint8 lbnhi:5, // top 5 bits of logical block number + lun:3; // logical unit number + uint16 lbnlo; // bottom 16 bits of logical block number + uint8 length; // data length + uint8 control; // control byte } SCSICDB6; typedef #include "vmware_pack_begin.h" struct { uint8 opcode; uint8 :5, - lun:3; + lun:3; uint32 lbn; uint8 reserved; - uint16 len; - uint8 ctrl; + uint16 length; + uint8 control; } #include "vmware_pack_end.h" SCSICDB10; @@ -308,11 +310,11 @@ typedef struct { uint8 opcode; uint8 :5, - lun:3; + lun:3; uint32 lbn; - uint32 len; + uint32 length; uint8 reserved; - uint8 ctrl; + uint8 control; } #include "vmware_pack_end.h" SCSICDB12; @@ -329,13 +331,13 @@ typedef struct { resv12:3, lun :3; uint8 pagecode; // only valid when cmddt or evdp is set - uint8 reserved; - uint8 len; - uint8 ctrl; + uint8 reserved; + uint8 length; + uint8 control; } SCSIInquiryCmd; -/* - * Format of the SCSI-3 INQUIRY command as defined in SPC-3 +/* + * Format of the SCSI-3 INQUIRY command as defined in SPC-3 */ typedef struct { uint8 opcode; // INQUIRY (0x12) @@ -343,81 +345,81 @@ typedef struct { obslt :1, // Obsolete as per SPC-3 resv :6; // The remaining bits are all RESERVED uint8 pagecode; // Only valid when evpd is set - uint8 lenMSB; // The SPC-3 spec has a 2 byte len field - uint8 len; - uint8 ctrl; + uint8 lengthMSB; // The SPC-3 spec has a 2 byte len field + uint8 length; + uint8 control; } SCSI3InquiryCmd; typedef struct { uint8 devclass :5, // SCSI device class -#define SCSI_CLASS_DISK 0x00 // disk drive -#define SCSI_CLASS_TAPE 0x01 // tape drive -#define SCSI_CLASS_PRINTER 0x02 // printer -#define SCSI_CLASS_CPU 0x03 // processor device -#define SCSI_CLASS_WORM 0x04 // WORM drive -#define SCSI_CLASS_CDROM 0x05 // CD-ROM drive -#define SCSI_CLASS_SCANNER 0x06 // scanner -#define SCSI_CLASS_OPTICAL 0x07 // optical disk -#define SCSI_CLASS_MEDIA 0x08 // media changer -#define SCSI_CLASS_COM 0x09 // communication device -#define SCSI_CLASS_RAID 0x0c // RAID controller (SCSI-3, reserved in SCSI-2) -#define SCSI_CLASS_SES 0x0d // SCSI Enclosure Services device (t10 SES) -#define SCSI_CLASS_UNKNOWN 0x1f // unknown device - pqual :3; // peripheral qualifier -#define SCSI_PQUAL_CONNECTED 0 // device described is connected to the LUN -#define SCSI_PQUAL_NOTCONNECTED 1 // target supports such a device, but none is connected -#define SCSI_PQUAL_NODEVICE 3 // target does not support a physical device for this LUN - uint8 :7, // reserved for SCSI-1 - rmb:1; // removable bit - uint8 ansi :3, // ANSI version -#define SCSI_ANSI_SCSI1 0x0 // device supports SCSI-1 -#define SCSI_ANSI_CCS 0x1 // device supports the CCS -#define SCSI_ANSI_SCSI2 0x2 // device supports SCSI-2 +#define SCSI_CLASS_DISK 0x00 // disk drive +#define SCSI_CLASS_TAPE 0x01 // tape drive +#define SCSI_CLASS_PRINTER 0x02 // printer +#define SCSI_CLASS_CPU 0x03 // processor device +#define SCSI_CLASS_WORM 0x04 // WORM drive +#define SCSI_CLASS_CDROM 0x05 // CD-ROM drive +#define SCSI_CLASS_SCANNER 0x06 // scanner +#define SCSI_CLASS_OPTICAL 0x07 // optical disk +#define SCSI_CLASS_MEDIA 0x08 // media changer +#define SCSI_CLASS_COM 0x09 // communication device +#define SCSI_CLASS_RAID 0x0c // RAID controller (SCSI-3, reserved in SCSI-2) +#define SCSI_CLASS_SES 0x0d // SCSI Enclosure Services device (t10 SES) +#define SCSI_CLASS_UNKNOWN 0x1f // unknown device + pqual :3; // peripheral qualifier +#define SCSI_PQUAL_CONNECTED 0 // device described is connected to the LUN +#define SCSI_PQUAL_NOTCONNECTED 1 // target supports such a device, but none is connected +#define SCSI_PQUAL_NODEVICE 3 // target does not support a physical device for this LUN + uint8 :7, // reserved for SCSI-1 + rmb :1; // removable bit + uint8 ansi :3, // ANSI version +#define SCSI_ANSI_SCSI1 0x0 // device supports SCSI-1 +#define SCSI_ANSI_CCS 0x1 // device supports the CCS +#define SCSI_ANSI_SCSI2 0x2 // device supports SCSI-2 #define SCSI_ANSI_SCSI3_SPC 0x3 // device supports SCSI-3 version SPC #define SCSI_ANSI_SCSI3_SPC2 0x4 // device supports SCSI-3 version SPC-2 #define SCSI_ANSI_SCSI3_SPC3 0x5 // device supports SCSI-3 version SPC-3 #define SCSI_ANSI_SCSI3_SPC4 0x6 // device supports SCSI-3 version SPC-4 - ecma :3, // ECMA version - iso :2; // ISO version + ecma :3, // ECMA version + iso :2; // ISO version uint8 dataformat :4, // format of the following standard data - :1, - naca :1, - tio :1, // device supports TERMINATE I/O PROCESS message - aen :1; // asynchronous event notification capability - uint8 optlen; // length of additional data that follows - uint8 :4, - tpgs :2, // Target Portal Group Support - :2; + :1, + naca :1, + tio :1, // device supports TERMINATE I/O PROCESS message + aen :1; // asynchronous event notification capability + uint8 optlen; // length of additional data that follows + uint8 :4, + tpgs :2, // Target Portal Group Support + :2; #define SCSI_TPGS_NONE 0x0 #define SCSI_TPGS_IMPLICIT_ONLY 0x1 -#define SCSI_TPGS_IMPLICIT SCSI_TPGS_IMPLICIT_ONLY +#define SCSI_TPGS_IMPLICIT SCSI_TPGS_IMPLICIT_ONLY #define SCSI_TPGS_EXPLICIT_ONLY 0x2 #define SCSI_TPGS_EXPLICIT SCSI_TPGS_EXPLICIT_ONLY #define SCSI_TPGS_BOTH_IMPLICIT_AND_EXPLICIT 0x3 #define SCSI_TPGS_BOTH SCSI_TPGS_BOTH_IMPLICIT_AND_EXPLICIT - uint8 adr16 :1, // device supports 16-bit wide SCSI addresses - adr32 :1, // device supports 32-bit wide SCSI addresses - arq :1, - mchngr :1, // device has attached media changer (SCSI-3) - dualp :1, // device is dual-ported (SCSI-3) - port :1, // port A or port B when dual-ported (SCSI-3) - :2; - uint8 sftr :1, // device supports soft reset capability - que :1, // device supports tagged commands - trndis :1, // device supports transfer disable messages (SCSI-3) - link :1, // device supports linked commands - sync :1, // device supports synchronous transfers - w16 :1, // device supports 16-bit wide SCSI data transfers - w32 :1, // device supports 32-bit wide SCSI data transfers - rel :1; // device supports relative addressing + uint8 adr16 :1, // device supports 16-bit wide SCSI addresses + adr32 :1, // device supports 32-bit wide SCSI addresses + arq :1, + mchngr :1, // device has attached media changer (SCSI-3) + dualp :1, // device is dual-ported (SCSI-3) + port :1, // port A or port B when dual-ported (SCSI-3) + :2; + uint8 sftr :1, // device supports soft reset capability + que :1, // device supports tagged commands + trndis :1, // device supports transfer disable messages (SCSI-3) + link :1, // device supports linked commands + sync :1, // device supports synchronous transfers + w16 :1, // device supports 16-bit wide SCSI data transfers + w32 :1, // device supports 32-bit wide SCSI data transfers + rel :1; // device supports relative addressing uint8 manufacturer[8]; // manufacturer's name in ascii #define SCSI_VENDOR_SZ sizeof(((SCSIInquiryResponse *) 0)->manufacturer) - uint8 product[16]; // product name in ascii + uint8 product[16]; // product name in ascii #define SCSI_MODEL_SZ sizeof(((SCSIInquiryResponse *) 0)->product) - uint8 revision[4]; // product version number in ascii - uint8 vendor1[20]; // vendor unique data (opaque) + uint8 revision[4]; // product version number in ascii + uint8 vendor1[20]; // vendor unique data (opaque) uint8 reserved[40]; -} SCSIInquiryResponse; // standard INQUIRY response format +} SCSIInquiryResponse; // standard INQUIRY response format /* * Same as SCSIInquiryResponse, except that only 36 bytes long. See above @@ -426,39 +428,39 @@ typedef struct { */ typedef struct { uint8 devclass :5, // SCSI device class - pqual :3; // peripheral qualifier - uint8 :7, // reserved for SCSI-1 - rmb:1; // removable bit - uint8 ansi :3, // ANSI version - ecma :3, // ECMA version - iso :2; // ISO version + pqual :3; // peripheral qualifier + uint8 :7, // reserved for SCSI-1 + rmb :1; // removable bit + uint8 ansi :3, // ANSI version + ecma :3, // ECMA version + iso :2; // ISO version uint8 dataformat :4, // format of the following standard data - :1, - naca :1, - tio :1, // device supports TERMINATE I/O PROCESS message - aen :1; // asynchronous event notification capability - uint8 optlen; // length of additional data that follows - uint8 :4, - tpgs :2, // Target Portal Group Support - :2; - uint8 adr16 :1, // device supports 16-bit wide SCSI addresses - adr32 :1, // device supports 32-bit wide SCSI addresses - arq :1, - mchngr :1, // device has attached media changer (SCSI-3) - dualp :1, // device is dual-ported (SCSI-3) - port :1, // port A or port B when dual-ported (SCSI-3) - :2; - uint8 sftr :1, // device supports soft reset capability - que :1, // device supports tagged commands - trndis :1, // device supports transfer disable messages (SCSI-3) - link :1, // device supports linked commands - sync :1, // device supports synchronous transfers - w16 :1, // device supports 16-bit wide SCSI data transfers - w32 :1, // device supports 32-bit wide SCSI data transfers - rel :1; // device supports relative addressing + :1, + naca :1, + tio :1, // device supports TERMINATE I/O PROCESS message + aen :1; // asynchronous event notification capability + uint8 optlen; // length of additional data that follows + uint8 :4, + tpgs :2, // Target Portal Group Support + :2; + uint8 adr16 :1, // device supports 16-bit wide SCSI addresses + adr32 :1, // device supports 32-bit wide SCSI addresses + arq :1, + mchngr :1, // device has attached media changer (SCSI-3) + dualp :1, // device is dual-ported (SCSI-3) + port :1, // port A or port B when dual-ported (SCSI-3) + :2; + uint8 sftr :1, // device supports soft reset capability + que :1, // device supports tagged commands + trndis :1, // device supports transfer disable messages (SCSI-3) + link :1, // device supports linked commands + sync :1, // device supports synchronous transfers + w16 :1, // device supports 16-bit wide SCSI data transfers + w32 :1, // device supports 32-bit wide SCSI data transfers + rel :1; // device supports relative addressing uint8 manufacturer[8]; // manufacturer's name in ascii - uint8 product[16]; // product name in ascii - uint8 revision[4]; // product version number in ascii + uint8 product[16]; // product name in ascii + uint8 revision[4]; // product version number in ascii } SCSIInquiry36Response; // standard INQUIRY response format #define SCSI_STANDARD_INQUIRY_MIN_LENGTH 36 @@ -470,17 +472,17 @@ typedef struct { /* * The following structures define the Page format supported by the * vscsi layer in vmkernel. The SPC-3 r23 spec defines a very generic - * layout of these pages, however the structures here are customized + * layout of these pages, however the structures here are customized * for vmkernel. */ typedef #include "vmware_pack_begin.h" struct SCSIInqPage00ResponseHeader { - uint8 devClass :5, - pQual :3; - uint8 pageCode; - uint8 reserved1; - uint8 pageLength; + uint8 devClass :5, + pQual :3; + uint8 pageCode; + uint8 reserved1; + uint8 pageLength; } #include "vmware_pack_end.h" SCSIInqPage00ResponseHeader; @@ -488,58 +490,58 @@ SCSIInqPage00ResponseHeader; typedef #include "vmware_pack_begin.h" struct SCSIInqPage80ResponseHeader { - uint8 devClass :5, - pQual :3; - uint8 pageCode; - uint8 reserved1; - uint8 pageLength; + uint8 devClass :5, + pQual :3; + uint8 pageCode; + uint8 reserved1; + uint8 pageLength; } #include "vmware_pack_end.h" SCSIInqPage80ResponseHeader; // Inquiry page 0x83: Identifier Type -#define SCSI_IDENTIFIERTYPE_VENDOR_SPEC 0x0 -#define SCSI_IDENTIFIERTYPE_T10 0x1 -#define SCSI_IDENTIFIERTYPE_EUI 0x2 -#define SCSI_IDENTIFIERTYPE_NAA 0x3 -#define SCSI_IDENTIFIERTYPE_RTPI 0x4 -#define SCSI_IDENTIFIERTYPE_TPG 0x5 -#define SCSI_IDENTIFIERTYPE_LUG 0x6 -#define SCSI_IDENTIFIERTYPE_MD5 0x7 -#define SCSI_IDENTIFIERTYPE_SNS 0x8 -#define SCSI_IDENTIFIERTYPE_RESERVED 0x9 -#define SCSI_IDENTIFIERTYPE_MAX SCSI_IDENTIFIERTYPE_RESERVED +#define SCSI_IDENTIFIERTYPE_VENDOR_SPEC 0x0 +#define SCSI_IDENTIFIERTYPE_T10 0x1 +#define SCSI_IDENTIFIERTYPE_EUI 0x2 +#define SCSI_IDENTIFIERTYPE_NAA 0x3 +#define SCSI_IDENTIFIERTYPE_RTPI 0x4 +#define SCSI_IDENTIFIERTYPE_TPG 0x5 +#define SCSI_IDENTIFIERTYPE_LUG 0x6 +#define SCSI_IDENTIFIERTYPE_MD5 0x7 +#define SCSI_IDENTIFIERTYPE_SNS 0x8 +#define SCSI_IDENTIFIERTYPE_RESERVED 0x9 +#define SCSI_IDENTIFIERTYPE_MAX SCSI_IDENTIFIERTYPE_RESERVED // Inquiry page 0x83: Transport Layer -#define SCSI_PROTOCOLID_FCP2 0x0 -#define SCSI_PROTOCOLID_SPI5 0x1 -#define SCSI_PROTOCOLID_SSAS3P 0x2 -#define SCSI_PROTOCOLID_SBP3 0x3 -#define SCSI_PROTOCOLID_SRP 0x4 -#define SCSI_PROTOCOLID_ISCSI 0x5 -#define SCSI_PROTOCOLID_SAS 0x6 -#define SCSI_PROTOCOLID_ADT 0x7 -#define SCSI_PROTOCOLID_ATA 0x8 -#define SCSI_PROTOCOLID_RESERVED 0xE -#define SCSI_PROTOCOLID_NO_PROTOCOL 0xF +#define SCSI_PROTOCOLID_FCP2 0x0 +#define SCSI_PROTOCOLID_SPI5 0x1 +#define SCSI_PROTOCOLID_SSAS3P 0x2 +#define SCSI_PROTOCOLID_SBP3 0x3 +#define SCSI_PROTOCOLID_SRP 0x4 +#define SCSI_PROTOCOLID_ISCSI 0x5 +#define SCSI_PROTOCOLID_SAS 0x6 +#define SCSI_PROTOCOLID_ADT 0x7 +#define SCSI_PROTOCOLID_ATA 0x8 +#define SCSI_PROTOCOLID_RESERVED 0xE +#define SCSI_PROTOCOLID_NO_PROTOCOL 0xF // Inquiry page 0x83: UUID Encoding -#define SCSI_CODESET_BINARY 0x1 -#define SCSI_CODESET_ASCII 0x2 -#define SCSI_CODESET_UTF8 0x3 -#define SCSI_CODESET_RESERVED 0xF +#define SCSI_CODESET_BINARY 0x1 +#define SCSI_CODESET_ASCII 0x2 +#define SCSI_CODESET_UTF8 0x3 +#define SCSI_CODESET_RESERVED 0xF // Inquiry page 0x83: UUID Entity -#define SCSI_ASSOCIATION_LUN 0x0 -#define SCSI_ASSOCIATION_TARGET_PORT 0x1 -#define SCSI_ASSOCIATION_TARGET_DEVICE 0x2 -#define SCSI_ASSOCIATION_RESERVED 0x3 +#define SCSI_ASSOCIATION_LUN 0x0 +#define SCSI_ASSOCIATION_TARGET_PORT 0x1 +#define SCSI_ASSOCIATION_TARGET_DEVICE 0x2 +#define SCSI_ASSOCIATION_RESERVED 0x3 typedef #include "vmware_pack_begin.h" struct SCSIInqPage83ResponseHeader { - uint8 devClass :5, - pQual :3; + uint8 devClass :5, + pQual :3; uint8 pageCode; uint16 pageLength; } @@ -579,11 +581,11 @@ typedef #include "vmware_pack_begin.h" struct SCSI2InqPage83ResponseDescriptor { /* Identification Descriptor follows */ - uint8 codeSet :4, - reserved :4; - uint8 idType :4, + uint8 codeSet :4, + reserved :4; + uint8 idType :4, association :2, - reserved1 :2; + reserved1 :2; uint8 reserved2; uint8 idLength; } @@ -641,12 +643,12 @@ SCSIReportLunsResponse; * may need them. */ typedef struct { - uint8 opcode; // operation code - uint8 :3, - dbd :1, // disable block descriptors - :1, - lun :3; // logical unit number - uint8 page :6, // page code + uint8 opcode; // operation code + uint8 :3, + dbd :1, // disable block descriptors + :1, + lun :3; // logical unit number + uint8 page :6, // page code #define SCSI_MS_PAGE_VENDOR 0x00 // vendor-specific (ALL) #define SCSI_MS_PAGE_RWERROR 0x01 // read/write error (DISK/TAPE/CDROM/OPTICAL) #define SCSI_MS_PAGE_CONNECT 0x02 // disconnect/connect (ALL) @@ -672,14 +674,14 @@ typedef struct { #define SCSI_MS_PAGE_CDCAPS 0x2a // CD-ROM capabilities and mechanical status (CDROM) // more defined... #define SCSI_MS_PAGE_ALL 0x3f // all available pages (ALL) - pcf :2; // page control field + pcf :2; // page control field #define SCSI_MS_PCF_CURRENT 0x00 // current values #define SCSI_MS_PCF_VOLATILE 0x01 // changeable values #define SCSI_MS_PCF_DEFAULT 0x02 // default values #define SCSI_MS_PCF_SAVED 0x03 // saved values uint8 subpage; - uint8 length; // data length - uint8 ctrl; // control byte + uint8 length; // data length + uint8 control; // control byte } SCSIModeSenseCmd; @@ -689,11 +691,11 @@ typedef struct { typedef #include "vmware_pack_begin.h" struct { - uint8 opcode; // FORMAT UNIT (0x4) - uint8 dlf :3, // defect list format - cmplst :1, // complete list - fmtdata:1, // format data - lun :3; + uint8 opcode; // FORMAT UNIT (0x4) + uint8 dlf :3, // defect list format + cmplst :1, // complete list + fmtdata:1, // format data + lun :3; uint8 vendor; uint16 interleave; uint8 control; @@ -705,81 +707,81 @@ SCSIFormatCmd; * Format Defect List header */ typedef struct { - uint8 reserved; - uint8 fov :1, // Format options valid - dpry :1, // disable primary - dcrt :1, // disable certification - stpf :1, // stop format - ip :1, // initialization pattern - dsp :1, // disable saving parameters - immed :1, // immediate - vs :1; - uint16 length; // Defect list length + uint8 reserved; + uint8 fov :1, // Format options valid + dpry :1, // disable primary + dcrt :1, // disable certification + stpf :1, // stop format + ip :1, // initialization pattern + dsp :1, // disable saving parameters + immed :1, // immediate + vs :1; + uint16 length; // Defect list length } SCSIDefectListHdr; -typedef +typedef #include "vmware_pack_begin.h" struct { - uint8 opcode; // operation code - uint8 :3, - dbd :1, // disable block descriptors - :1, - lun :3; // logical unit number - uint8 page :6, // page code - pcf :2; // page control field + uint8 opcode; // operation code + uint8 :3, + dbd :1, // disable block descriptors + :1, + lun :3; // logical unit number + uint8 page :6, // page code + pcf :2; // page control field uint8 reserved[4]; uint16 length; // data length - uint8 ctrl; // control byte + uint8 control; // control byte } #include "vmware_pack_end.h" SCSIModeSense10Cmd; typedef struct { - uint8 opcode; // operation code - uint8 sp :1, // save pages - :3, - pf :1, // page format - lun :3; // logical unit number + uint8 opcode; // operation code + uint8 sp :1, // save pages + :3, + pf :1, // page format + lun :3; // logical unit number uint8 reserved[2]; - uint8 len; // data length - uint8 ctrl; // control byte + uint8 length; // data length + uint8 control; // control byte } SCSIModeSelectCmd; -typedef +typedef #include "vmware_pack_begin.h" struct { - uint8 opcode; // operation code - uint8 sp :1, // save pages - :3, - pf :1, // page format - lun :3; // logical unit number + uint8 opcode; // operation code + uint8 sp :1, // save pages + :3, + pf :1, // page format + lun :3; // logical unit number uint8 reserved[5]; - uint16 len; // data length - uint8 ctrl; // control byte + uint16 length; // data length + uint8 control; // control byte } #include "vmware_pack_end.h" SCSIModeSelect10Cmd; typedef struct { - uint8 len; // data length + uint8 len; // data length uint8 mediaType; uint8 devSpecific; // device specific - uint8 bdLen; // block descriptor length + uint8 bdLen; // block descriptor length } SCSIModeHeader6; typedef struct { - uint16 len; // data length + uint16 len; // data length uint8 mediaType; uint8 devSpecific; // device specific uint16 reserved; - uint16 bdLen; // block descriptor length + uint16 bdLen; // block descriptor length } SCSIModeHeader10; typedef struct { - uint8 reserved1:4; - uint8 dpofua:1; // disable page out / force unit access - uint8 reserved2:2; - uint8 wp:1; // write protected + uint8 reserved1:4, + dpofua :1, // disable page out / force unit access + reserved2:2, + wp :1; // write protected } SCSIBlockModeSenseDeviceParameter; /* @@ -788,11 +790,11 @@ typedef struct { typedef #include "vmware_pack_begin.h" struct { - uint8 opcode:8; // operation code - uint8 ext:1, - tid:3, - tparty:1, - lun:3; // logical unit number + uint8 opcode:8; // operation code + uint8 ext :1, + tid :3, + tparty:1, + lun :3; // logical unit number uint8 resid; uint16 extlen; uint8 control; @@ -805,11 +807,11 @@ SCSIReserveCmd; * types (a fourth is added in SCSI-3). The following structures * define these pages as sent+received with MODE SENSE and SELECT. */ -typedef struct { // connect/disconnect page - uint8 page :6, // page code: 0x02 - :1, - ps :1; - uint8 len; // page length (0x0e) +typedef struct { // connect/disconnect page + uint8 page :6, // page code: 0x02 + :1, + ps :1; + uint8 len; // page length (0x0e) uint8 bufFull; uint8 bufEmpty; uint16 maxBusInactiveTime; @@ -817,159 +819,159 @@ typedef struct { // connect/disconnect page uint16 maxConnectTime; uint16 maxBurstLength; uint8 dtdc :3, - dimm :1, // disconnect immediate (SCSI-3) - :3, - emdp :1; // enable MODIFY DATA POINTER (SCSI-3) + dimm :1, // disconnect immediate (SCSI-3) + :3, + emdp :1; // enable MODIFY DATA POINTER (SCSI-3) } SCSIConnectPage; -typedef struct { // peripheral device page - uint8 page :6, // page code: 0x09 - :1, - ps :1; - uint8 len; // page length (n-1) - uint16 ifID; // physical interface identifier +typedef struct { // peripheral device page + uint8 page :6, // page code: 0x09 + :1, + ps :1; + uint8 len; // page length (n-1) + uint16 ifID; // physical interface identifier uint8 reserved[4]; uint8 undefined[1]; // variable-length vendor-specific data } SCSIPeriphPage; typedef struct { - uint8 page :6, // page code: 0x0a - :1, - ps :1; - uint8 len; // page length (0x06) + uint8 page :6, // page code: 0x0a + :1, + ps :1; + uint8 len; // page length (0x06) uint8 rlec :1, - gltsd :1, - :2, - :4; - uint8 dque :1, // disable tagged queuing - qerr :1, // - :2, - qalg :4; // queue algorithm - uint8 eaenp :1, // error AEN permission - uaaenp:1, // unit attention AEN permission - raenp :1, // ready AEN permission - :4, - eeca :1; // + gltsd :1, + :2, + :4; + uint8 dque :1, // disable tagged queuing + qerr :1, // + :2, + qalg :4; // queue algorithm + uint8 eaenp :1, // error AEN permission + uaaenp:1, // unit attention AEN permission + raenp :1, // ready AEN permission + :4, + eeca :1; // uint8 reserved; uint16 aenWaitTime; // AEN waiting time after initialization uint16 busyTimeout; // busy timeout in 100ms (SCSI-3) } SCSIControlPage; typedef struct { - uint8 page :6, // page code: 0x09 - :1, - ps :1; - uint8 len; // page length 0x06 - uint8 dcr :1, // error recover parameters - dte :1, // diable transfer on seeing recovered error - per :1, // post error: report recovered errors - :1, - rc :1, // read continuous: don't delay data transfer to correct errors - tb :1, // transfer block when unrecovered - :2; + uint8 page :6, // page code: 0x09 + :1, + ps :1; + uint8 len; // page length 0x06 + uint8 dcr :1, // error recover parameters + dte :1, // diable transfer on seeing recovered error + per :1, // post error: report recovered errors + :1, + rc :1, // read continuous: don't delay data transfer to correct errors + tb :1, // transfer block when unrecovered + :2; uint8 readRetries; // read retry count uint8 reserved[4]; } SCSIRWErrorPage; typedef struct { - uint8 page :6, // page code: 0x0d - :1, - ps :1; - uint8 len; // page length 0x06 - uint8 :8; - uint8 inactive:4, // head inactivity timeout - :4; + uint8 page :6, // page code: 0x0d + :1, + ps :1; + uint8 len; // page length 0x06 + uint8 :8; + uint8 inactive :4, // head inactivity timeout + :4; uint16 secsPerMinute; // number of MSF seconds per MSF minute uint16 framesPerSec; // number of MSF frames per MSF second } SCSICDROMPage; typedef struct { - uint8 page :6, // page code: 0x0e - :1, - ps :1; - uint8 len; // page length 0x0e - uint8 :1, - sotb :1, - immediate:1, - :5; - uint8 :8; - uint8 :8; + uint8 page :6, // page code: 0x0e + :1, + ps :1; + uint8 len; // page length 0x0e + uint8 :1, + sotb :1, + immediate:1, + :5; + uint8 :8; + uint8 :8; uint8 lbaFactor:4, - :3, - aprv :1; - uint16 lbaPerSec; // number of LBAs per second - uint8 port0 :4, // output port 0 select - :4; + :3, + aprv :1; + uint16 lbaPerSec; // number of LBAs per second + uint8 port0 :4, // output port 0 select + :4; uint8 port0Volume; - uint8 port1 :4, // output port 1 select - :4; + uint8 port1 :4, // output port 1 select + :4; uint8 port1Volume; - uint8 port2 :4, // output port 2 select - :4; + uint8 port2 :4, // output port 2 select + :4; uint8 port2Volume; - uint8 port3 :4, // output port 3 select - :4; + uint8 port3 :4, // output port 3 select + :4; uint8 port3Volume; } SCSICDROMAudioPage; typedef struct { - uint8 page :6, // page code: 0x2a - :1, - ps :1; - uint8 len; // page length 0x12 - uint8 cdrRd :1,// CD-R read per Orange Book Part II - cdeRd :1,// CD-E read per Orange Book Part III - method2 :1,// CD-R media w/ Addressing Method 2 - :5; - uint8 cdrWr :1,// CD-R write per Orange Book Part II - cdeWr :1,// CD-E write per Orange Book Part III - :6; - uint8 audioPlay :1,// drive is capable of audio play - composite :1,// drive is capable of delivering composite audio+video - digPort1 :1,// drive supports digital output (IEC958) on port 1 - digPort2 :1,// drive supports digital output on port 2 - mode2Form1 :1,// drive reads Mode 2 Form 1 (XA) format - mode2Form2 :1,// drive reads Mode 2 Form 2 format - multiSession:1,// drive reads multi-session or Photo-CD discs - :1; - uint8 cdDA :1,// CD-DA commands (Red Book) supported - daAccu :1,// CD-DA stream is accurate - rwSupported :1,// R-W supported - rwDeinter :1,// R-W subchannel data de-interleaved and corrected - c2Ptrs :1,// C2 Error Pointers supported - isrc :1,// drive returns International Standard Recording Code Info - upc :1,// drive returns Media Catalog Number - :1; - uint8 lock :1,// PREVENT/ALLOW commands lock media into drive - lockState :1,// current state of drive - jumpers :1,// state of prevent/allow jumpers - eject :1,// drive can eject disc via START/STOP command - :1, - loadType :3;// loading mechanism type - uint8 sv :1,// separate volume - scm :1,// separate channel mute - sdp :1,// supports disc present in MECHANISM STATUS command - sss :1,// s/w slot selection w/ LOAD/UNLOCK command - :4; - uint16 maxSpeed; // maximum speed supported (in KB/s) + uint8 page :6, // page code: 0x2a + :1, + ps :1; + uint8 len; // page length 0x12 + uint8 cdrRd :1, // CD-R read per Orange Book Part II + cdeRd :1, // CD-E read per Orange Book Part III + method2 :1, // CD-R media w/ Addressing Method 2 + :5; + uint8 cdrWr :1, // CD-R write per Orange Book Part II + cdeWr :1, // CD-E write per Orange Book Part III + :6; + uint8 audioPlay:1, // drive is capable of audio play + composite:1, // drive is capable of delivering composite audio+video + digPort1 :1, // drive supports digital output (IEC958) on port 1 + digPort2 :1, // drive supports digital output on port 2 + mode2Form1:1, // drive reads Mode 2 Form 1 (XA) format + mode2Form2:1, // drive reads Mode 2 Form 2 format + multiSession:1,// drive reads multi-session or Photo-CD discs + :1; + uint8 cdDA :1, // CD-DA commands (Red Book) supported + daAccu :1, // CD-DA stream is accurate + rwSupported:1, // R-W supported + rwDeinter:1, // R-W subchannel data de-interleaved and corrected + c2Ptrs :1, // C2 Error Pointers supported + isrc :1, // drive returns International Standard Recording Code Info + upc :1, // drive returns Media Catalog Number + :1; + uint8 lock :1, // PREVENT/ALLOW commands lock media into drive + lockState:1, // current state of drive + jumpers :1, // state of prevent/allow jumpers + eject :1, // drive can eject disc via START/STOP command + :1, + loadType :3; // loading mechanism type + uint8 sv :1, // separate volume + scm :1, // separate channel mute + sdp :1, // supports disc present in MECHANISM STATUS command + sss :1, // s/w slot selection w/ LOAD/UNLOCK command + :4; + uint16 maxSpeed; // maximum speed supported (in KB/s) uint16 numVolLevels; // number of volume levels supported - uint16 bufSize; // buffer size supported by drive (KBytes) - uint16 curSpeed; // current speed selected (in KB/s) + uint16 bufSize; // buffer size supported by drive (KBytes) + uint16 curSpeed; // current speed selected (in KB/s) uint8 reserved; - uint8 :1,// format of digital data output - bck :1,// data is valid on the falling edge of BCK - rck :1,// HIGH on LRCK indicates left channel - lsbf :1,// LSB first - length :2, - :2; + uint8 :1, // format of digital data output + bck :1, // data is valid on the falling edge of BCK + rck :1, // HIGH on LRCK indicates left channel + lsbf :1, // LSB first + length :2, + :2; uint8 reserved2[2]; } SCSICDROMCapabilitiesPage; typedef struct { - uint8 page :6, // page code: 0x03 - :1, - ps :1; - uint8 len; // page length 0x16 + uint8 page :6, // page code: 0x03 + :1, + ps :1; + uint8 len; // page length 0x16 uint16 tracksPerZone; uint16 repSectorsPerZone; uint16 repTracksPerZone; @@ -979,46 +981,46 @@ typedef struct { uint16 interleave; uint16 trackSkew; uint16 cylinderSkew; - uint8 :3, - surf :1, - rmb :1, - hsec :1, - ssec :1; + uint8 :3, + surf :1, + rmb :1, + hsec :1, + ssec :1; uint8 reserved[3]; } SCSIFormatPage; typedef uint8 uint24[3]; typedef struct { - uint8 page :6, // page code: 0x04 - :1, - ps :1; - uint8 len; // page length 0x16 - uint24 cylinders; // number of cylinders - uint8 heads; // number of heads + uint8 page :6, // page code: 0x04 + :1, + ps :1; + uint8 len; // page length 0x16 + uint24 cylinders; // number of cylinders + uint8 heads; // number of heads uint24 writeCompCylinder; // starting cylinder for write compensation uint24 writeCurCylinder; // starting cylinder for reduce write current uint16 stepRate; - uint24 landingZone; // cylinder number of landing zone - uint8 rpl :1, - :7; - uint8 rotOffset; // rotational offset - uint8 :8; - uint16 rotRate; // medium rotation rate + uint24 landingZone; // cylinder number of landing zone + uint8 rpl :1, + :7; + uint8 rotOffset; // rotational offset + uint8 :8; + uint16 rotRate; // medium rotation rate uint8 reserved[2]; } SCSIGeometryPage; typedef struct { - uint8 page :6, // page code: 0x08 - :1, - ps :1; - uint8 len; // page length 0x0a (0x12 for SCSI-3) - uint8 rcd :1, - mf :1, - wce :1, - :5; - uint8 readPri:4, // read retention priority - writePri:4; // write retention priority + uint8 page :6, // page code: 0x08 + :1, + ps :1; + uint8 len; // page length 0x0a (0x12 for SCSI-3) + uint8 rcd :1, + mf :1, + wce :1, + :5; + uint8 readPri :4, // read retention priority + writePri :4; // write retention priority uint16 prefetchDisable;// disable pre-fetch transfer length uint16 prefetchMin; // pre-fetch minimum uint16 prefetchMax; // pre-fetch maximum @@ -1026,101 +1028,102 @@ typedef struct { } SCSICachePage; typedef struct { - uint8 page :6, // page code: 0x08 - :1, - ps :1; - uint8 len; // page length 0x16 - uint8 :6, - lpn :1, - nd :1; - uint8 :8; - uint16 maxNotches; // maximum number of notches + uint8 page :6, // page code: 0x08 + :1, + ps :1; + uint8 len; // page length 0x16 + uint8 :6, + lpn :1, + nd :1; + uint8 :8; + uint16 maxNotches; // maximum number of notches uint16 activeNotch; - uint32 activeStart; // beginning of active notch - uint32 activeEnd; // end of active notch + uint32 activeStart;// beginning of active notch + uint32 activeEnd; // end of active notch } SCSINotchPage; typedef struct { - uint8 page :6, // page code: 0x06 - :1, - ps :1; - uint8 len; // page length 0x02 + uint8 page :6, // page code: 0x06 + :1, + ps :1; + uint8 len; // page length 0x02 uint8 rubr :1, - :7; - uint8 :8; + :7; + uint8 :8; } SCSIOpticalPage; + typedef struct { - uint8 page :6, // page code: 0x0f - :1, - ps :1; - uint8 len; // page length 0x0e - uint8 :6, - dcc :1, - dce :1; - uint8 :5, - red :2, - dde :1; + uint8 page :6, // page code: 0x0f + :1, + ps :1; + uint8 len; // page length 0x0e + uint8 :6, + dcc :1, + dce :1; + uint8 :5, + red :2, + dde :1; uint8 compAlg[4]; uint8 decompAlg[4]; uint8 reserved[4]; } SCSICompressionPage; typedef struct { - uint8 page :6, // page code: 0x10 - :1, - ps :1; - uint8 len; // page length 0x0e - uint8 format:5, // active format - car :1, - cap :1, - :1; - uint8 partition; // active partition - uint8 wbeRatio; // write buffer empty ratio - uint8 rbeRatio; // read buffer empty ratio + uint8 page :6, // page code: 0x10 + :1, + ps :1; + uint8 len; // page length 0x0e + uint8 format:5, // active format + car :1, + cap :1, + :1; + uint8 partition; // active partition + uint8 wbeRatio; // write buffer empty ratio + uint8 rbeRatio; // read buffer empty ratio uint16 writeDelay; - uint8 rew :1, - rb0 :1, - sofc :2, - avc :1, - rsmk :1, - bis :1, - dbr :1; + uint8 rew :1, + rb0 :1, + sofc :2, + avc :1, + rsmk :1, + bis :1, + dbr :1; uint8 gapSize; - uint8 :3, - sew :1, - eeg :1, - eod :3; + uint8 :3, + sew :1, + eeg :1, + eod :3; uint24 bufSizeAtEW; uint8 compression; - uint8 :8; + uint8 :8; } SCSIDeviceConfigPage; typedef struct { - uint8 page :6, // page code: 0x03 - :1, - ps :1; - uint8 len; // page length 0x06 - uint8 unit; // measurement unit - uint8 :8; + uint8 page :6, // page code: 0x03 + :1, + ps :1; + uint8 len; // page length 0x06 + uint8 unit; // measurement unit + uint8 :8; uint16 divisor; - uint16 :16; + uint16 :16; } SCSIUnitsPage; /* * Format of START STOP UNIT (0x1b). */ -typedef +typedef #include "vmware_pack_begin.h" struct { - uint8 opcode; // 0x1b - uint8 immed:1, - rsvd:7; + uint8 opcode; // 0x1b + uint8 immed :1, + rsvd :7; uint8 reserved[2]; - uint8 start:1, - loej:1, // load/eject - rsvd1:2, - power:4; + uint8 start :1, + loej :1, // load/eject + rsvd1 :2, + power :4; uint8 control; } #include "vmware_pack_end.h" @@ -1130,10 +1133,10 @@ SCSIStartStopUnitCmd; /* * Format of ALLOW PREVENT MEDIUM REMOVAL (0x1e). */ -typedef +typedef #include "vmware_pack_begin.h" struct { - uint8 opcode; // 0x1e + uint8 opcode; // 0x1e uint8 reserved[3]; uint8 prevent:2, :6; @@ -1148,18 +1151,18 @@ SCSIMediumRemovalCmd; * These are defined here because multiple SCSI devices * need them. */ -typedef +typedef #include "vmware_pack_begin.h" struct { - uint8 opcode; // 0x25 + uint8 opcode; // 0x25 uint8 rel :1, - :4, - lun :3; + :4, + lun :3; #define SCSI_RW10_MAX_LBN 0xffffffffu uint32 lbn; uint8 reserved[2]; uint8 pmi :1, - :7; + :7; uint8 control; } #include "vmware_pack_end.h" @@ -1170,24 +1173,24 @@ typedef struct { uint32 blocksize; } SCSIReadCapacityResponse; -typedef +typedef #include "vmware_pack_begin.h" struct { - uint8 opcode; // 0x9e + uint8 opcode; // 0x9e #define SCSI_READ_CAPACITY16_SERVICE_ACTION 0x10 uint8 action:5, - :3; + :3; uint64 lbn; uint32 len; uint8 pmi :1, - rel :1, - :6; + rel :1, + :6; uint8 control; } #include "vmware_pack_end.h" SCSIReadCapacity16Cmd; -typedef +typedef #include "vmware_pack_begin.h" struct { uint64 lbn; @@ -1201,27 +1204,17 @@ SCSIReadCapacity16Response; * request. These are defined here because multiple SCSI * devices need them. */ -typedef -#include "vmware_pack_begin.h" -struct { - uint32 opcode:8, - lun:3, - lbn:21; - uint8 length; - uint8 control; -} -#include "vmware_pack_end.h" -SCSIReadWrite6Cmd; +typedef SCSICDB6 SCSIReadWrite6Cmd; -typedef +typedef #include "vmware_pack_begin.h" struct { uint8 opcode; uint8 rel :1, - :2, - flua :1, - dpo :1, - lun :3; + :2, + flua :1, + dpo :1, + lun :3; uint32 lbn; uint8 reserved; uint16 length; @@ -1230,15 +1223,15 @@ struct { #include "vmware_pack_end.h" SCSIReadWrite10Cmd; -typedef +typedef #include "vmware_pack_begin.h" struct { uint8 opcode; uint8 rel :1, - :2, - flua :1, - dpo :1, - lun :3; + :2, + flua :1, + dpo :1, + lun :3; uint32 lbn; uint32 length; uint8 reserved; @@ -1247,15 +1240,15 @@ struct { #include "vmware_pack_end.h" SCSIReadWrite12Cmd; -typedef +typedef #include "vmware_pack_begin.h" struct { uint8 opcode; uint8 rel :1, - :2, - flua :1, - dpo :1, - :3; + :2, + flua :1, + dpo :1, + :3; uint64 lbn; uint32 length; uint8 reserved; @@ -1264,22 +1257,22 @@ struct { #include "vmware_pack_end.h" SCSIReadWrite16Cmd; -typedef +typedef #include "vmware_pack_begin.h" struct { uint8 opcode; - uint8 xtnt :1, // extent-based reservation - ptyID :3, // 3rd party reservation ID - pty :1, // 3rd party reservation - lun :3; // logical unit number - uint8 resvID; // SCSI-3: reservation ID - uint16 resvListLen; // SCSI-3: reservation list length - uint8 ctrl; // control byte + uint8 xtnt :1, // extent-based reservation + ptyID :3, // 3rd party reservation ID + pty :1, // 3rd party reservation + lun :3; // logical unit number + uint8 resvID; // SCSI-3: reservation ID + uint16 resvListLen; // SCSI-3: reservation list length + uint8 control; // control byte } #include "vmware_pack_end.h" SCSIReserveUnitCmd; -typedef +typedef #include "vmware_pack_begin.h" struct { uint8 opcode; @@ -1289,12 +1282,12 @@ struct { lun :3; // logical unit number uint8 resvID; // SCSI-3: reservation ID uint8 reserved[2]; - uint8 ctrl; // control byte -} + uint8 control; // control byte +} #include "vmware_pack_end.h" SCSIReleaseUnitCmd; -typedef +typedef #include "vmware_pack_begin.h" struct { uint8 opcode; @@ -1305,8 +1298,8 @@ struct { pf :1, // page format lun :3; // logical unit number uint8 reserved; - uint16 len; // data length - uint8 ctrl; // control byte + uint16 length; // data length + uint8 control; // control byte } #include "vmware_pack_end.h" SCSISendDiagnosticCmd; @@ -1323,8 +1316,8 @@ struct { lun :3; // logical unit number uint32 lbn; // logical block address uint8 reserved; - uint16 len; // verification length - uint8 ctrl; // control byte + uint16 length; // verification length + uint8 control; // control byte } #include "vmware_pack_end.h" SCSIVerify10Cmd; @@ -1333,7 +1326,7 @@ typedef #include "vmware_pack_begin.h" struct { uint8 opcode; - uint8 polled :1, // asynchronous or not + uint8 polled :1, // asynchronous or not :7; uint8 reserved0[2]; #define SCSI_GESN_CLASS_RSVD0 (1 << 0) @@ -1346,14 +1339,14 @@ struct { #define SCSI_GESN_CLASS_RSVD1 (1 << 7) uint8 notifyClassReq; // the class of events we are interested in uint8 reserved1[2]; - uint16 length; // allocation length + uint16 length; // allocation length uint8 control; } #include "vmware_pack_end.h" SCSIGetEventStatusNotificationCmd; /* - * Format of Persistent Reservation Commands per SPC-3 r23, required for + * Format of Persistent Reservation Commands per SPC-3 r23, required for * virtualizing reservations. */ @@ -1365,8 +1358,8 @@ typedef enum { READ_FULL_STATUS = 0x3 } SCSIPersistentReserveInServiceAction; -/* - * Persistent reservation type codes +/* + * Persistent reservation type codes */ typedef enum { WRITE_EXCL = 0x1, @@ -1377,16 +1370,16 @@ typedef enum { EXCL_ACCESS_ALL_REG = 0x8 } SCSIPersistentReserveTypeCode; -typedef +typedef #include "vmware_pack_begin.h" -struct { - uint8 opcode; +struct { + uint8 opcode; uint8 serviceAction :5, reserved :3; uint8 reserved1[5]; uint16 allocationLength; uint8 control; -} +} #include "vmware_pack_end.h" SCSIPersistentReserveInCmd; @@ -1403,7 +1396,7 @@ typedef enum { } SCSIPersistentReserveOutServiceAction; -typedef +typedef #include "vmware_pack_begin.h" struct { uint8 opcode; @@ -1412,9 +1405,9 @@ struct { uint8 type :4, scope :4; uint8 reserved1[2]; - uint32 parameterListLength; + uint32 parameterListLength; uint8 control; -} +} #include "vmware_pack_end.h" SCSIPersistentReserveOutCmd; @@ -1436,11 +1429,11 @@ struct { * following are true: * a. the SPEC_I_PT but is set to 0 * b. service action is not REGISTER AND MOVE - * + * * This is currently the only supported mode in the vmkernel, * so no additional parameter data is included in this struct */ -} +} #include "vmware_pack_end.h" SCSIPersistentReserveOutPList; @@ -1455,7 +1448,7 @@ struct { uint8 type :4, scope :4; uint8 obsolete1[2]; -} +} #include "vmware_pack_end.h" SCSIPRReadReservationResp; @@ -1470,13 +1463,13 @@ SCSIPRReadReservationResp; * of sense data at a time; the base SCSI device support invalidates * this data structure before each SCSI operation as needed. */ -typedef +typedef #include "vmware_pack_begin.h" struct { - uint8 error :7, // 0x70 for current command, 0x71 for earlier command -#define SCSI_SENSE_ERROR_CURCMD 0x70 // sense data is for "current command" -#define SCSI_SENSE_ERROR_PREVCMD 0x71 // sense data is for an earlier command - valid :1; // sense data valid + uint8 error :7, // 0x70 for current command, 0x71 for earlier command +#define SCSI_SENSE_ERROR_CURCMD 0x70 // sense data is for "current command" +#define SCSI_SENSE_ERROR_PREVCMD 0x71 // sense data is for an earlier command + valid :1; // sense data valid /* NB: Please Note that the valid bit above does NOT tell you whether * the sense is actually valid and thus the name is really badly chosen * (even though it is the official name from the SCSI II specification). @@ -1485,25 +1478,25 @@ struct { * we have seen that many tape drives are capable of returning sense * without this bit set.... */ - uint8 segment; // segment number - uint8 key :4, // sense key - :1, - ili :1, - eom :1, - filmrk :1; - uint8 info[4]; // general information - uint8 optLen; // length of optional data that follows - uint8 cmdInfo[4]; // command-specific information - uint8 code; // sense code - uint8 xcode; // extended sense code - uint8 fru; // - uint8 bitpos :3, - bpv :1, - :2, - cd :1, // 1 if error in command, 0 if in data - sksv :1; // sense key specific data is valid - uint16 epos; // offset of first byte in error - + uint8 segment; // segment number + uint8 key :4, // sense key + :1, + ili :1, + eom :1, + filmrk :1; + uint8 info[4]; // general information + uint8 optLen; // length of optional data that follows + uint8 cmdInfo[4]; // command-specific information + uint8 code; // sense code + uint8 xcode; // extended sense code + uint8 fru; // + uint8 bitpos :3, + bpv :1, + :2, + cd :1, // 1 if error in command, 0 if in data + sksv :1; // sense key specific data is valid + uint16 epos; // offset of first byte in error + // Some vendors want to return additional data which // requires a sense buffer of up to 64 bytes. uint8 additional[46]; @@ -1647,6 +1640,129 @@ struct { SCSIRDSDVDPhysicalInfoLeadin; +/* + * MSF structure for CDs. + */ +typedef +#include "vmware_pack_begin.h" +struct { + uint8 minute; + uint8 second; + uint8 frame; +} +#include "vmware_pack_end.h" +SCSICDMSF; + + +/* + * ReadCD packet data. + */ +typedef +#include "vmware_pack_begin.h" +struct { + uint8 opcode; + uint8 obsolete:1, + dap:1, + expectedSectorType:3, + reserved1:3; + uint32 lbn; + uint8 length[3]; + uint8 reserved2:1, + c2errors:2, + mainChannelSelectionBits:5; + uint8 subChannelSelectionBits:3, + reserved3:5; + uint8 control; +} +#include "vmware_pack_end.h" +SCSIReadCDCmd; + + +/* + * ReadCDMSF packet data. + */ +typedef +#include "vmware_pack_begin.h" +struct { + uint8 opcode; + uint8 obsolete:1, + dap:1, + expectedSectorType:3, + reserved1:3; + uint8 reserved; + SCSICDMSF start; + SCSICDMSF end; + uint8 reserved2:1, + c2errors:2, + mainChannelSelectionBits:5; + uint8 subChannelSelectionBits:3, + reserved3:5; + uint8 control; +} +#include "vmware_pack_end.h" +SCSIReadCDMSFCmd; + + +/* + * ReadTOC packet data. + */ +typedef +#include "vmware_pack_begin.h" +struct { + uint8 opcode; + uint8 reserved1:1, + msf:1, + reserved2:6; + uint8 format:3, /* MMC says 4 bits for eons. Original ATAPI is only 3 bits. */ + reserved3:5; + uint8 reserved4[3]; + uint8 trackNumber; + uint16 allocationLength; + uint8 control; +} +#include "vmware_pack_end.h" +SCSIReadTOCCmd; + + +/* + * ReadSubChannel packet data. + */ +typedef +#include "vmware_pack_begin.h" +struct { + uint8 opcode; + uint8 reserved1:1, + msf:1, + reserved2:6; + uint8 reserved3:6, + subq:1, + reserved4:1; + uint8 format; + uint8 reserved5[2]; + uint8 trackNumber; + uint16 allocationLength; + uint8 control; +} +#include "vmware_pack_end.h" +SCSIReadSubChannelCmd; + + +/* + * PlayMSF packet data. + */ +typedef +#include "vmware_pack_begin.h" +struct { + uint8 opcode; + uint8 reserved[2]; + SCSICDMSF start; + SCSICDMSF end; + uint8 control; +} +#include "vmware_pack_end.h" +SCSIPlayMSFCmd; + + /* * Host and device status definitions. * @@ -1693,13 +1809,13 @@ typedef enum { SDSTAT_CHECK = 0x02, // check condition SDSTAT_CONDITION_MET = 0x04, // condition met SDSTAT_BUSY = 0x08, // device busy - SDSTAT_INTERMEDIATE = 0x10, + SDSTAT_INTERMEDIATE = 0x10, SDSTAT_INTERMEDIATE_CONDITION = 0x14, SDSTAT_RESERVATION_CONFLICT = 0x18, // device reserved by another host SDSTAT_COMMAND_TERMINATED = 0x22, - SDSTAT_TASK_SET_FULL = 0x28, - SDSTAT_ACA_ACTIVE = 0x30, - SDSTAT_TASK_ABORTED = 0x40, + SDSTAT_TASK_SET_FULL = 0x28, + SDSTAT_ACA_ACTIVE = 0x30, + SDSTAT_TASK_ABORTED = 0x40, } SCSIDeviceStatus; typedef enum { @@ -1719,7 +1835,7 @@ typedef enum { /* *--------------------------------------------------------------------------- - * + * * SCSICdb_IsRead -- * * This function returns TRUE if the scsi command passed as an argument is @@ -1737,7 +1853,7 @@ typedef enum { static INLINE Bool SCSICdb_IsRead(uint8 cdb0) // IN { - return cdb0 == SCSI_CMD_READ6 + return cdb0 == SCSI_CMD_READ6 || cdb0 == SCSI_CMD_READ10 || cdb0 == SCSI_CMD_READ12 || cdb0 == SCSI_CMD_READ16; @@ -1746,7 +1862,7 @@ SCSICdb_IsRead(uint8 cdb0) // IN /* *--------------------------------------------------------------------------- - * + * * SCSICdb_IsWrite -- * * This function returns TRUE if the scsi command passed as an argument is @@ -1764,7 +1880,7 @@ SCSICdb_IsRead(uint8 cdb0) // IN static INLINE Bool SCSICdb_IsWrite(uint8 cdb0) // IN { - return cdb0 == SCSI_CMD_WRITE6 + return cdb0 == SCSI_CMD_WRITE6 || cdb0 == SCSI_CMD_WRITE10 || cdb0 == SCSI_CMD_WRITE12 || cdb0 == SCSI_CMD_WRITE16; @@ -1795,6 +1911,51 @@ SCSICdb_IsRW(uint8 cdb0) // IN } +/* + *--------------------------------------------------------------------------- + * + * SCSICdb_GetCDBLength -- + * + * This function returns length of specified command. Multibyte + * CDB (0x7F) is reported as reserved command. + * + * Results: + * 6 for commands 00-1F + * 10 for commands 20-5F + * 16 for commands 80-9F + * 12 for commands A0-BF + * SCSI_GRP_RESERVED for commands 60-7F + * SCSI_GRP_VENDOR for commands C0-FF + * Both SCSI_GRP_RESERVED & SCSI_GRP_VENDOR are guarateed to have + * bigger value than 16. + * + * Side effects: + * None. + * + *--------------------------------------------------------------------------- + */ + +#define SCSI_GRP_RESERVED 64 +#define SCSI_GRP_VENDOR 65 + +static INLINE size_t +SCSICdb_GetCDBLength(uint8 cdb0) // IN +{ + static const unsigned char lengths[] = { + 6, /* 00 - 1F */ + 10, /* 20 - 3F */ + 10, /* 40 - 5F */ + SCSI_GRP_RESERVED, /* 60 - 7F */ + 16, /* 80 - 9F */ + 12, /* A0 - BF */ + SCSI_GRP_VENDOR, /* C0 - DF */ + SCSI_GRP_VENDOR, /* E0 - FF */ + }; + + return lengths[cdb0 >> 5]; +} + + /* *--------------------------------------------------------------------------- * @@ -1838,7 +1999,7 @@ SCSICdb_GetLengthFieldOffset(uint8 cmd) * * SCSI3InquiryLen -- * - * Returns 16-bit allocation length specified in SCSI3 Inquriy CMD cmd + * Returns 16-bit allocation length specified in SCSI3 Inquriy CMD cmd * * Results: * 16-bit allocation length. @@ -1850,18 +2011,18 @@ SCSICdb_GetLengthFieldOffset(uint8 cmd) */ static INLINE uint16 -SCSI3InquiryLen(SCSI3InquiryCmd *inqCmd) // IN +SCSI3InquiryLen(const SCSI3InquiryCmd *inqCmd) // IN { - return (inqCmd->lenMSB << 8) + inqCmd->len; + return (inqCmd->lengthMSB << 8) + inqCmd->length; } -typedef +typedef #include "vmware_pack_begin.h" struct SCSICmdInfo { uint8 code; uint8 xferType; - char *name; + const char *name; uint8 emulation; } #include "vmware_pack_end.h" @@ -1883,259 +2044,259 @@ extern SCSICmdInfo scsiCmdInfo[256]; #define SCSI_CMD_INFO_DATA \ {SCSI_CMD_TEST_UNIT_READY, SCSI_XFER_NONE, "TEST UNIT READY", SCSI_EMULATE}, \ {SCSI_CMD_REZERO_UNIT, SCSI_XFER_NONE, "REWIND/REZERO UNIT", SCSI_DONT_EMULATE}, \ - {0x02, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_REQUEST_SENSE, SCSI_XFER_TOHOST, "REQUEST SENSE", SCSI_EMULATE}, \ - {SCSI_CMD_FORMAT_UNIT, SCSI_XFER_TODEVICE, "FORMAT UNIT", SCSI_EMULATE}, \ - {SCSI_CMD_READ_BLOCKLIMITS, SCSI_XFER_TOHOST, "READ BLOCK LIMITS", SCSI_DONT_EMULATE},\ - {0x06, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_INIT_ELEMENT_STATUS, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ6, SCSI_XFER_TOHOST, "READ(6)", SCSI_EMULATE}, \ - {0x09, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_WRITE6, SCSI_XFER_TODEVICE, "WRITE(6)", SCSI_EMULATE}, \ - {SCSI_CMD_SLEW_AND_PRINT, SCSI_XFER_TODEVICE, NULL, SCSI_DONT_EMULATE}, \ - {0x0c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x0d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x0e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_REVERSE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SYNC_BUFFER, SCSI_XFER_NONE, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SPACE, SCSI_XFER_NONE, "SPACE", SCSI_DONT_EMULATE}, \ + {0x02, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_REQUEST_SENSE, SCSI_XFER_TOHOST, "REQUEST SENSE", SCSI_EMULATE}, \ + {SCSI_CMD_FORMAT_UNIT, SCSI_XFER_TODEVICE, "FORMAT UNIT", SCSI_EMULATE}, \ + {SCSI_CMD_READ_BLOCKLIMITS, SCSI_XFER_TOHOST, "READ BLOCK LIMITS", SCSI_DONT_EMULATE}, \ + {0x06, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_INIT_ELEMENT_STATUS, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ6, SCSI_XFER_TOHOST, "READ(6)", SCSI_EMULATE}, \ + {0x09, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_WRITE6, SCSI_XFER_TODEVICE, "WRITE(6)", SCSI_EMULATE}, \ + {SCSI_CMD_SLEW_AND_PRINT, SCSI_XFER_TODEVICE, NULL, SCSI_DONT_EMULATE}, \ + {0x0c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x0d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x0e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ_REVERSE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SYNC_BUFFER, SCSI_XFER_NONE, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SPACE, SCSI_XFER_NONE, "SPACE", SCSI_DONT_EMULATE}, \ {SCSI_CMD_INQUIRY, SCSI_XFER_TOHOST, "INQUIRY", SCSI_EMULATE}, \ - {0x13, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_RECOVER_BUFFERED, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_MODE_SELECT, SCSI_XFER_TODEVICE, "MODE SELECT(6)", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_RESERVE_UNIT, SCSI_XFER_NONE, "RESERVE(6)", SCSI_EMULATE}, \ - {SCSI_CMD_RELEASE_UNIT, SCSI_XFER_NONE, "RELEASE(6)", SCSI_EMULATE}, \ - {SCSI_CMD_COPY, SCSI_XFER_AUTO, "COPY AND VERIFY", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_ERASE, SCSI_XFER_NONE, "ERASE", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_MODE_SENSE, SCSI_XFER_TOHOST, "MODE SENSE(6)", SCSI_EMULATE}, \ - {SCSI_CMD_SCAN, SCSI_XFER_TODEVICE, NULL, SCSI_EMULATE}, \ + {0x13, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_RECOVER_BUFFERED, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_MODE_SELECT, SCSI_XFER_TODEVICE, "MODE SELECT(6)", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_RESERVE_UNIT, SCSI_XFER_NONE, "RESERVE(6)", SCSI_EMULATE}, \ + {SCSI_CMD_RELEASE_UNIT, SCSI_XFER_NONE, "RELEASE(6)", SCSI_EMULATE}, \ + {SCSI_CMD_COPY, SCSI_XFER_AUTO, "COPY AND VERIFY", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_ERASE, SCSI_XFER_NONE, "ERASE", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_MODE_SENSE, SCSI_XFER_TOHOST, "MODE SENSE(6)", SCSI_EMULATE}, \ + {SCSI_CMD_SCAN, SCSI_XFER_TODEVICE, NULL, SCSI_EMULATE}, \ {SCSI_CMD_RECV_DIAGNOSTIC, SCSI_XFER_AUTO, "RECEIVE DIAGNOSTIC RESULTS", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SEND_DIAGNOSTIC, SCSI_XFER_TODEVICE, "SEND DIAGNOSTIC", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SEND_DIAGNOSTIC, SCSI_XFER_TODEVICE, "SEND DIAGNOSTIC", SCSI_DONT_EMULATE}, \ {SCSI_CMD_MEDIUM_REMOVAL, SCSI_XFER_NONE, "LOCK/UNLOCK DOOR", SCSI_DONT_EMULATE_DONT_LOG}, \ - {0x1f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x20, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x21, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x22, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x1f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x20, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x21, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x22, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ {SCSI_CMD_READ_FORMAT_CAPACITIES, SCSI_XFER_TOHOST, "READ FORMAT CAPACITIES", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SET_WINDOW, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_CAPACITY, SCSI_XFER_TOHOST, "READ CAPACITY", SCSI_EMULATE}, \ - {0x26, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x27, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ10, SCSI_XFER_TOHOST, "READ(10)", SCSI_EMULATE}, \ - {SCSI_CMD_READ_GENERATION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_WRITE10, SCSI_XFER_TODEVICE, "WRITE(10)", SCSI_EMULATE}, \ - {SCSI_CMD_SEEK10, SCSI_XFER_NONE, NULL, SCSI_DONT_EMULATE}, \ - {0x2c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_UPDATED_BLOCK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_WRITE_VERIFY, SCSI_XFER_AUTO, "WRITE VERIFY", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_VERIFY, SCSI_XFER_NONE, "VERIFY", SCSI_EMULATE}, \ - {SCSI_CMD_SEARCH_DATA_HIGH, SCSI_XFER_AUTO, "SEARCH HIGH", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SEARCH_DATA_EQUAL, SCSI_XFER_AUTO, "SEARCH EQUAL", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SEARCH_DATA_LOW, SCSI_XFER_AUTO, "SEARCH LOW", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SET_LIMITS, SCSI_XFER_AUTO, "SET LIMITS", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_POSITION, SCSI_XFER_TOHOST, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SYNC_CACHE, SCSI_XFER_NONE, "SYNC CACHE", SCSI_EMULATE}, \ - {SCSI_CMD_LOCKUNLOCK_CACHE, SCSI_XFER_AUTO, "LOCK/UNLOCK CACHE", SCSI_DONT_EMULATE},\ + {SCSI_CMD_SET_WINDOW, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ_CAPACITY, SCSI_XFER_TOHOST, "READ CAPACITY", SCSI_EMULATE}, \ + {0x26, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x27, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ10, SCSI_XFER_TOHOST, "READ(10)", SCSI_EMULATE}, \ + {SCSI_CMD_READ_GENERATION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_WRITE10, SCSI_XFER_TODEVICE, "WRITE(10)", SCSI_EMULATE}, \ + {SCSI_CMD_SEEK10, SCSI_XFER_NONE, NULL, SCSI_DONT_EMULATE}, \ + {0x2c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ_UPDATED_BLOCK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_WRITE_VERIFY, SCSI_XFER_AUTO, "WRITE VERIFY", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_VERIFY, SCSI_XFER_NONE, "VERIFY", SCSI_EMULATE}, \ + {SCSI_CMD_SEARCH_DATA_HIGH, SCSI_XFER_AUTO, "SEARCH HIGH", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SEARCH_DATA_EQUAL, SCSI_XFER_AUTO, "SEARCH EQUAL", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SEARCH_DATA_LOW, SCSI_XFER_AUTO, "SEARCH LOW", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SET_LIMITS, SCSI_XFER_AUTO, "SET LIMITS", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ_POSITION, SCSI_XFER_TOHOST, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SYNC_CACHE, SCSI_XFER_NONE, "SYNC CACHE", SCSI_EMULATE}, \ + {SCSI_CMD_LOCKUNLOCK_CACHE, SCSI_XFER_AUTO, "LOCK/UNLOCK CACHE", SCSI_DONT_EMULATE}, \ {SCSI_CMD_READ_DEFECT_DATA, SCSI_XFER_AUTO, "READ DEFECT DATA", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_MEDIUM_SCAN, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_COMPARE, SCSI_XFER_AUTO, "COMPARE", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_COPY_VERIFY, SCSI_XFER_AUTO, "COPY AND VERIFY", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_WRITE_BUFFER, SCSI_XFER_AUTO, "WRITE BUFFER", SCSI_DONT_EMULATE_DONT_LOG}, \ - {SCSI_CMD_READ_BUFFER, SCSI_XFER_AUTO, "READ BUFFER", SCSI_DONT_EMULATE_DONT_LOG}, \ - {SCSI_CMD_UPDATE_BLOCK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_LONG, SCSI_XFER_AUTO, "READ LONG", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_WRITE_LONG, SCSI_XFER_AUTO, "WRITE LONG", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_CHANGE_DEF, SCSI_XFER_NONE, "CHANGE DEFINITION", SCSI_DONT_EMULATE},\ - {SCSI_CMD_WRITE_SAME, SCSI_XFER_AUTO, "WRITE SAME", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_SUBCHANNEL, SCSI_XFER_TOHOST, "READ SUBCHANNEL", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_TOC, SCSI_XFER_TOHOST, "READ TOC", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_HEADER, SCSI_XFER_TOHOST, "READ HEADER", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_PLAY_AUDIO10, SCSI_XFER_NONE, "PLAY AUDIO(10)", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_GET_CONFIGURATION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_PLAY_AUDIO_MSF, SCSI_XFER_NONE, "PLAY AUDIO MSF", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_MEDIUM_SCAN, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_COMPARE, SCSI_XFER_AUTO, "COMPARE", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_COPY_VERIFY, SCSI_XFER_AUTO, "COPY AND VERIFY", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_WRITE_BUFFER, SCSI_XFER_AUTO, "WRITE BUFFER", SCSI_DONT_EMULATE_DONT_LOG}, \ + {SCSI_CMD_READ_BUFFER, SCSI_XFER_AUTO, "READ BUFFER", SCSI_DONT_EMULATE_DONT_LOG}, \ + {SCSI_CMD_UPDATE_BLOCK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ_LONG, SCSI_XFER_AUTO, "READ LONG", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_WRITE_LONG, SCSI_XFER_AUTO, "WRITE LONG", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_CHANGE_DEF, SCSI_XFER_NONE, "CHANGE DEFINITION", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_WRITE_SAME, SCSI_XFER_AUTO, "WRITE SAME", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ_SUBCHANNEL, SCSI_XFER_TOHOST, "READ SUBCHANNEL", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ_TOC, SCSI_XFER_TOHOST, "READ TOC", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ_HEADER, SCSI_XFER_TOHOST, "READ HEADER", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_PLAY_AUDIO10, SCSI_XFER_NONE, "PLAY AUDIO(10)", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_GET_CONFIGURATION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_PLAY_AUDIO_MSF, SCSI_XFER_NONE, "PLAY AUDIO MSF", SCSI_DONT_EMULATE}, \ {SCSI_CMD_PLAY_AUDIO_TRACK, SCSI_XFER_AUTO, "PLAY AUDIO TRACK", SCSI_DONT_EMULATE}, \ {SCSI_CMD_PLAY_AUDIO_RELATIVE, SCSI_XFER_AUTO, "PLAY AUDIO RELATIVE", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_PAUSE, SCSI_XFER_NONE, "PAUSE/RESUME", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_LOG_SELECT, SCSI_XFER_TODEVICE, "LOG SELECT", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_LOG_SENSE, SCSI_XFER_TOHOST, "LOG SENSE", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_STOP_PLAY, SCSI_XFER_NONE, "STOP PLAY", SCSI_DONT_EMULATE}, \ - {0x4f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x50, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_DISC_INFO, SCSI_XFER_TOHOST, "CDR INFO", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_TRACK_INFO, SCSI_XFER_TOHOST, "TRACK INFO", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_RESERVE_TRACK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x54, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_MODE_SELECT10, SCSI_XFER_TODEVICE, "MODE SELECT(10)", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_RESERVE_UNIT10, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_RELEASE_UNIT10, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x58, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x59, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_MODE_SENSE10, SCSI_XFER_TOHOST, "MODE SENSE(10)", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_CLOSE_SESSION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_BUFFER_CAPACITY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SEND_CUE_SHEET, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_GET_EVENT_STATUS_NOTIFICATION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_PAUSE, SCSI_XFER_NONE, "PAUSE/RESUME", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_LOG_SELECT, SCSI_XFER_TODEVICE, "LOG SELECT", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_LOG_SENSE, SCSI_XFER_TOHOST, "LOG SENSE", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_STOP_PLAY, SCSI_XFER_NONE, "STOP PLAY", SCSI_DONT_EMULATE}, \ + {0x4f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x50, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ_DISC_INFO, SCSI_XFER_TOHOST, "CDR INFO", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ_TRACK_INFO, SCSI_XFER_TOHOST, "TRACK INFO", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_RESERVE_TRACK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x54, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_MODE_SELECT10, SCSI_XFER_TODEVICE, "MODE SELECT(10)", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_RESERVE_UNIT10, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_RELEASE_UNIT10, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x58, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x59, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_MODE_SENSE10, SCSI_XFER_TOHOST, "MODE SENSE(10)", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_CLOSE_SESSION, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ_BUFFER_CAPACITY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SEND_CUE_SHEET, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ {SCSI_CMD_PERSISTENT_RESERVE_IN, SCSI_XFER_TOHOST, "PERSISTENT RESERVE IN", SCSI_EMULATE}, \ - {SCSI_CMD_PERSISTENT_RESERVE_OUT, SCSI_XFER_TODEVICE, "PERSISTENT RESERVE OUT", SCSI_EMULATE}, \ - {0x60, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x61, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x62, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x63, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x64, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x65, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x66, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x67, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x68, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x69, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x6a, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x6b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x6c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x6d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x6e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x6f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x70, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x71, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x72, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x73, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x74, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x75, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x76, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x77, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x78, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x79, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x7a, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x7b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x7c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x7d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x7e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x7f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x80, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x81, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x82, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x83, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x84, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x85, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x86, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x87, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ16, SCSI_XFER_TOHOST, "READ(16)", SCSI_EMULATE}, \ - {0x89, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_WRITE16, SCSI_XFER_TODEVICE, "WRITE(16)", SCSI_EMULATE}, \ - {0x8b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x8c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x8d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x8e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_VERIFY16, SCSI_XFER_NONE, "VERIFY(16)", SCSI_EMULATE}, \ - {0x90, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x91, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x92, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x93, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x94, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x95, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x96, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x97, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x98, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x99, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x9a, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x9b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x9c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0x9d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_CAPACITY16, SCSI_XFER_TOHOST, "READ CAPACITY 16", SCSI_EMULATE}, \ - {0x9f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_REPORT_LUNS, SCSI_XFER_AUTO, "REPORT LUNS", SCSI_EMULATE},\ - {SCSI_CMD_BLANK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xa2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SEND_KEY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_REPORT_KEY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_PLAY_AUDIO12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_LOADCD, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xa7, SCSI_XFER_AUTO, "MOVE MEDIUM", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_PLAY_TRACK_RELATIVE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_WRITE12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xab, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_ERASE12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_DVD_STRUCTURE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_WRITE_VERIFY12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_VERIFY12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SEARCH_DATA_HIGH12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SEARCH_DATA_EQUAL12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SEARCH_DATA_LOW12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SET_LIMITS12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_PERSISTENT_RESERVE_OUT, SCSI_XFER_TODEVICE, "PERSISTENT RESERVE OUT", SCSI_EMULATE}, \ + {0x60, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x61, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x62, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x63, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x64, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x65, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x66, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x67, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x68, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x69, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x6a, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x6b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x6c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x6d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x6e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x6f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x70, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x71, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x72, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x73, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x74, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x75, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x76, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x77, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x78, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x79, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x7a, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x7b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x7c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x7d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x7e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x7f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x80, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x81, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x82, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x83, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x84, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x85, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x86, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x87, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ16, SCSI_XFER_TOHOST, "READ(16)", SCSI_EMULATE}, \ + {0x89, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_WRITE16, SCSI_XFER_TODEVICE, "WRITE(16)", SCSI_EMULATE}, \ + {0x8b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x8c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x8d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x8e, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_VERIFY16, SCSI_XFER_NONE, "VERIFY(16)", SCSI_EMULATE}, \ + {0x90, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x91, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x92, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x93, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x94, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x95, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x96, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x97, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x98, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x99, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x9a, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x9b, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x9c, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0x9d, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ_CAPACITY16, SCSI_XFER_TOHOST, "READ CAPACITY 16", SCSI_EMULATE}, \ + {0x9f, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_REPORT_LUNS, SCSI_XFER_AUTO, "REPORT LUNS", SCSI_EMULATE}, \ + {SCSI_CMD_BLANK, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xa2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SEND_KEY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_REPORT_KEY, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_PLAY_AUDIO12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_LOADCD, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xa7, SCSI_XFER_AUTO, "MOVE MEDIUM", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_PLAY_TRACK_RELATIVE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_WRITE12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xab, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_ERASE12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ_DVD_STRUCTURE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_WRITE_VERIFY12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_VERIFY12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SEARCH_DATA_HIGH12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SEARCH_DATA_EQUAL12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SEARCH_DATA_LOW12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SET_LIMITS12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ {0xb4, SCSI_XFER_AUTO, "READ ELEMENT STATUS", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_REQUEST_VOLUME_ELEMENT_ADDR, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SET_STREAMING, SCSI_XFER_TODEVICE, "SET STREAMING", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_DEFECT_DATA12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SELECT_CDROM_SPEED, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_CD_MSF, SCSI_XFER_TOHOST, "READ CD MSF", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_AUDIO_SCAN, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SET_CDROM_SPEED, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {SCSI_CMD_PLAY_CD, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_REQUEST_VOLUME_ELEMENT_ADDR, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SET_STREAMING, SCSI_XFER_TODEVICE, "SET STREAMING", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ_DEFECT_DATA12, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SELECT_CDROM_SPEED, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_READ_CD_MSF, SCSI_XFER_TOHOST, "READ CD MSF", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_AUDIO_SCAN, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SET_CDROM_SPEED, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {SCSI_CMD_PLAY_CD, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ {SCSI_CMD_MECH_STATUS, SCSI_XFER_TOHOST, "MECHANISM STATUS", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_READ_CD, SCSI_XFER_TOHOST, "READ CD MSF", SCSI_DONT_EMULATE}, \ - {SCSI_CMD_SEND_DVD_STRUCTURE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xc0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xc1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xc2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xc3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xc4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xc5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xc6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xc7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xc8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xc9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xca, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xcb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xcc, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xcd, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xce, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xcf, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xd0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xd1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xd2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xd3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xd4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xd5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xd6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xd7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xd8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xd9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xda, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xdb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xdc, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xdd, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xde, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xdf, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xe0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xe1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xe2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xe3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xe4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xe5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xe6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xe7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xe8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xe9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xea, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xeb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xec, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xed, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xee, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xef, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xf0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xf1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xf2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xf3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xf4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xf5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xf6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xf7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xf8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xf9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xfa, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xfb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xfc, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xfd, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xfe, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ - {0xff, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, + {SCSI_CMD_READ_CD, SCSI_XFER_TOHOST, "READ CD", SCSI_DONT_EMULATE}, \ + {SCSI_CMD_SEND_DVD_STRUCTURE, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xc0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xc1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xc2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xc3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xc4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xc5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xc6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xc7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xc8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xc9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xca, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xcb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xcc, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xcd, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xce, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xcf, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xd0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xd1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xd2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xd3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xd4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xd5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xd6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xd7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xd8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xd9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xda, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xdb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xdc, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xdd, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xde, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xdf, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xe0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xe1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xe2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xe3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xe4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xe5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xe6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xe7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xe8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xe9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xea, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xeb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xec, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xed, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xee, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xef, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xf0, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xf1, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xf2, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xf3, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xf4, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xf5, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xf6, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xf7, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xf8, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xf9, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xfa, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xfb, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xfc, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xfd, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xfe, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, \ + {0xff, SCSI_XFER_AUTO, NULL, SCSI_DONT_EMULATE}, #endif diff --git a/open-vm-tools/modules/linux/shared/compat_pci.h b/open-vm-tools/modules/linux/shared/compat_pci.h index 52b77e0ae..fc88ae8e9 100644 --- a/open-vm-tools/modules/linux/shared/compat_pci.h +++ b/open-vm-tools/modules/linux/shared/compat_pci.h @@ -29,6 +29,12 @@ # include #endif +#if KERNEL_VERSION(2, 6, 6) <= LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) +# ifndef DMA_BIT_MASK +# define DMA_BIT_MASK(n) DMA_##n##BIT_MASK +# endif +#endif + /* 2.0.x has useless struct pci_dev; remap it to our own */ #ifndef KERNEL_2_1 diff --git a/open-vm-tools/modules/linux/shared/compat_skbuff.h b/open-vm-tools/modules/linux/shared/compat_skbuff.h index 685be7b76..f4623d5d7 100644 --- a/open-vm-tools/modules/linux/shared/compat_skbuff.h +++ b/open-vm-tools/modules/linux/shared/compat_skbuff.h @@ -37,7 +37,9 @@ #define compat_skb_end_pointer(skb) skb_end_pointer(skb) #define compat_skb_ip_header(skb) ((struct iphdr *)skb_network_header(skb)) #define compat_skb_tcp_header(skb) ((struct tcphdr *)skb_transport_header(skb)) -#define compat_skb_reset_mac_header(skb) skb_reset_mac_header(skb) +#define compat_skb_reset_mac_header(skb) skb_reset_mac_header(skb) +#define compat_skb_reset_network_header(skb) skb_reset_network_header(skb) +#define compat_skb_reset_transport_header(skb) skb_reset_transport_header(skb) #define compat_skb_set_network_header(skb, off) skb_set_network_header(skb, off) #define compat_skb_set_transport_header(skb, off) skb_set_transport_header(skb, off) #else @@ -52,6 +54,8 @@ #define compat_skb_ip_header(skb) (skb)->nh.iph #define compat_skb_tcp_header(skb) (skb)->h.th #define compat_skb_reset_mac_header(skb) ((skb)->mac.raw = (skb)->data) +#define compat_skb_reset_network_header(skb) ((skb)->nh.raw = (skb)->data) +#define compat_skb_reset_transport_header(skb) ((skb)->h.raw = (skb)->data) #define compat_skb_set_network_header(skb, off) ((skb)->nh.raw = (skb)->data + (off)) #define compat_skb_set_transport_header(skb, off) ((skb)->h.raw = (skb)->data + (off)) #endif diff --git a/open-vm-tools/modules/linux/shared/vmci_call_defs.h b/open-vm-tools/modules/linux/shared/vmci_call_defs.h index 9829d4918..89542d1f8 100644 --- a/open-vm-tools/modules/linux/shared/vmci_call_defs.h +++ b/open-vm-tools/modules/linux/shared/vmci_call_defs.h @@ -85,7 +85,7 @@ typedef struct VMCIDatagramWellKnownMapMsg { * Struct size is 16 bytes. All fields in struct are aligned to their natural * alignment. */ -typedef struct VMCIResourcesQueuryHdr { +typedef struct VMCIResourcesQueryHdr { VMCIDatagram hdr; uint32 numResources; uint32 _padding; diff --git a/open-vm-tools/modules/linux/shared/vmci_infrastructure.h b/open-vm-tools/modules/linux/shared/vmci_infrastructure.h index 6560e2bc0..67b6be9b7 100644 --- a/open-vm-tools/modules/linux/shared/vmci_infrastructure.h +++ b/open-vm-tools/modules/linux/shared/vmci_infrastructure.h @@ -42,6 +42,7 @@ typedef enum { VMCIOBJ_CONTEXT, VMCIOBJ_PROCESS, VMCIOBJ_DATAGRAM_PROCESS, + VMCIOBJ_SOCKET, VMCIOBJ_NOT_SET, } VMCIObjType; diff --git a/open-vm-tools/modules/linux/shared/vmci_iocontrols.h b/open-vm-tools/modules/linux/shared/vmci_iocontrols.h index 777d70db6..979f8df5c 100644 --- a/open-vm-tools/modules/linux/shared/vmci_iocontrols.h +++ b/open-vm-tools/modules/linux/shared/vmci_iocontrols.h @@ -255,6 +255,7 @@ enum IOCTLCmd_VMCI { * or opening the device in kernel-mode, and are always in UNICODE. */ #define VMCI_DEVICE_NAME TEXT("\\\\.\\VMCI") +#define VMCI_DEVICE_NAME_NT L"\\??\\VMCI" #define VMCI_DEVICE_NAME_PATH L"\\Device\\vmci" #define VMCI_DEVICE_LINK_PATH L"\\DosDevices\\vmci" @@ -333,24 +334,26 @@ enum IOCTLCmd_VMCI { VMCIIOCTL_BUFFERED(SOCKETS_IOCTL) #define IOCTL_VMCI_SOCKETS_LISTEN \ VMCIIOCTL_BUFFERED(SOCKETS_LISTEN) -#define IOCTL_VMCI_SOCKETS_RECV \ - VMCIIOCTL_BUFFERED(SOCKETS_RECV) #define IOCTL_VMCI_SOCKETS_RECV_FROM \ VMCIIOCTL_BUFFERED(SOCKETS_RECV_FROM) #define IOCTL_VMCI_SOCKETS_SELECT \ VMCIIOCTL_BUFFERED(SOCKETS_SELECT) -#define IOCTL_VMCI_SOCKETS_SEND \ - VMCIIOCTL_BUFFERED(SOCKETS_SEND) #define IOCTL_VMCI_SOCKETS_SEND_TO \ VMCIIOCTL_BUFFERED(SOCKETS_SEND_TO) #define IOCTL_VMCI_SOCKETS_SET_SOCK_OPT \ VMCIIOCTL_BUFFERED(SOCKETS_SET_SOCK_OPT) #define IOCTL_VMCI_SOCKETS_SHUTDOWN \ VMCIIOCTL_BUFFERED(SOCKETS_SHUTDOWN) -#define IOCTL_VMCI_SOCKETS_SOCKET \ - VMCIIOCTL_BUFFERED(SOCKETS_SOCKET) /* END VMCI SOCKETS */ + +/* + * For accessing VMCIOBJ_SOCKET in IOCTLs. Both functions take a file object's + * fs context and get or set the socket. + */ +PVOID VMCIFsContext_GetSocket(PVOID fsContext); +void VMCIFsContext_SetSocket(PVOID fsContext, PVOID socket); + #endif // _WIN32 diff --git a/open-vm-tools/modules/linux/shared/vmci_queue_pair.h b/open-vm-tools/modules/linux/shared/vmci_queue_pair.h index be69c284e..fa2dc1924 100644 --- a/open-vm-tools/modules/linux/shared/vmci_queue_pair.h +++ b/open-vm-tools/modules/linux/shared/vmci_queue_pair.h @@ -261,6 +261,33 @@ AddPointer(Atomic_uint64 *var, // IN: } VMCIQueue; # endif #else + /* + * VMCIQueuePair_QueueIsMapped() + * + * This macro will return TRUE if a queue created by either the + * guest or host has had the memory for the queue pair mapped by the + * VMX and made avaiable to the host by way of the SetPageFile + * ioctls. + * + * After SetPageFile, the queue memory will remain available to the + * host until the host detaches. On Linux and Mac OS platforms the + * memory for the queue pair remains available to the host driver + * after the VMX process for the guest goes away. On Windows, the + * memory is copied (under the protection of a mutex) so that the + * host can continue to operate on the queues after the VMX is gone. + * + * The version of the VMCIQueue data structure which is provided by + * the VMCI kernel module is protected by the VMCI + * QueuePairList_Lock and the VMCI QueuePairList_FindEntry() + * function. Therefore, host-side clients shouldn't be able to + * access the structure after it's gone. And, the memory the + * queueHeaderPtr points to is torn down (and freed) after the entry + * has been removed from the QueuePairList and just before the entry + * itself is deallocated. + */ + +# define VMCIQueuePair_QueueIsMapped(q) ((q)->queueHeaderPtr != NULL) + # if defined(__linux__) && defined(__KERNEL__) /* * Linux Kernel Host @@ -277,7 +304,6 @@ AddPointer(Atomic_uint64 *var, // IN: VMCIQueueHeader *queueHeaderPtr; struct page **page; } VMCIQueue; -# define VMCIQueuePair_QueueIsMapped(q) ((q)->page != NULL) # elif defined __APPLE__ /* * Mac OS Host @@ -303,7 +329,6 @@ AddPointer(Atomic_uint64 *var, // IN: IOMemoryDescriptor *pages; IOMemoryMap *header; } VMCIQueue; -# define VMCIQueuePair_QueueIsMapped(q) ((q)->pages) # else /* * Windows Host @@ -353,7 +378,6 @@ AddPointer(Atomic_uint64 *var, // IN: FAST_MUTEX __mutex; /* Don't touch except to init */ } VMCIQueue; #define VMCIQueuePair_EnqueueToDevNull(q) ((q)->enqueueToDevNull) -#define VMCIQueuePair_QueueIsMapped(q) ((q)->buffer != NULL) # endif #endif diff --git a/open-vm-tools/modules/linux/vmblock/linux/control.c b/open-vm-tools/modules/linux/vmblock/linux/control.c index 522fd73f8..cd7ebaa39 100644 --- a/open-vm-tools/modules/linux/vmblock/linux/control.c +++ b/open-vm-tools/modules/linux/vmblock/linux/control.c @@ -27,8 +27,9 @@ #include #include #include -#include "compat_uaccess.h" -#include "compat_fs.h" +#include + +#include #include "vmblockInt.h" #include "block.h" @@ -295,14 +296,14 @@ ControlFileOpWrite(struct file *file, // IN: Opened file, used for ID * side-stepping the syscall auditing and doing the copy from user space * ourself. Change this back once we GPL the module. */ - filename = compat___getname(); + filename = __getname(); if (!filename) { Warning("ControlFileOpWrite: Could not obtain memory for filename.\n"); return -ENOMEM; } /* - * XXX: compat___getname() returns a pointer to a PATH_MAX-sized buffer. + * XXX: __getname() returns a pointer to a PATH_MAX-sized buffer. * Hard-coding this size is also gross, but it's our only option here and * InodeOpLookup() already set a bad example by doing this. */ @@ -338,7 +339,7 @@ ControlFileOpWrite(struct file *file, // IN: Opened file, used for ID } exit: - compat___putname(filename); + __putname(filename); return ret; } diff --git a/open-vm-tools/modules/linux/vmblock/linux/dentry.c b/open-vm-tools/modules/linux/vmblock/linux/dentry.c index 961d59087..66537c8c8 100644 --- a/open-vm-tools/modules/linux/vmblock/linux/dentry.c +++ b/open-vm-tools/modules/linux/vmblock/linux/dentry.c @@ -24,19 +24,15 @@ */ #include "driver-config.h" -#include "compat_fs.h" -#include "compat_namei.h" +#include +#include "compat_namei.h" #include "vmblockInt.h" #include "filesystem.h" #include "block.h" -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75) static int DentryOpRevalidate(struct dentry *dentry, struct nameidata *nd); -#else -static int DentryOpRevalidate(struct dentry *dentry, int flags); -#endif struct dentry_operations LinkDentryOps = { .d_revalidate = DentryOpRevalidate, @@ -62,15 +58,9 @@ struct dentry_operations LinkDentryOps = { *---------------------------------------------------------------------------- */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75) static int DentryOpRevalidate(struct dentry *dentry, // IN: dentry revalidating struct nameidata *nd) // IN: lookup flags & intent -#else -static int -DentryOpRevalidate(struct dentry *dentry, // IN: dentry revalidating - int flags) // IN: lookup flags (e.g., LOOKUP_CONTINUE) -#endif { VMBlockInodeInfo *iinfo; struct nameidata actualNd; @@ -111,14 +101,10 @@ DentryOpRevalidate(struct dentry *dentry, // IN: dentry revalidating if (actualDentry && actualDentry->d_op && actualDentry->d_op->d_revalidate) { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75) return actualDentry->d_op->d_revalidate(actualDentry, nd); -#else - return actualDentry->d_op->d_revalidate(actualDentry, flags); -#endif } - if (compat_path_lookup(iinfo->name, 0, &actualNd)) { + if (path_lookup(iinfo->name, 0, &actualNd)) { LOG(4, "DentryOpRevalidate: [%s] no longer exists\n", iinfo->name); return 0; } diff --git a/open-vm-tools/modules/linux/vmblock/linux/file.c b/open-vm-tools/modules/linux/vmblock/linux/file.c index 6b651f0a2..c55ae57ea 100644 --- a/open-vm-tools/modules/linux/vmblock/linux/file.c +++ b/open-vm-tools/modules/linux/vmblock/linux/file.c @@ -25,8 +25,9 @@ #include "driver-config.h" #include -#include "compat_fs.h" -#include "compat_sched.h" +#include +#include +#include #include "vmblockInt.h" #include "filesystem.h" diff --git a/open-vm-tools/modules/linux/vmblock/linux/filesystem.c b/open-vm-tools/modules/linux/vmblock/linux/filesystem.c index 850c97174..53840fdfb 100644 --- a/open-vm-tools/modules/linux/vmblock/linux/filesystem.c +++ b/open-vm-tools/modules/linux/vmblock/linux/filesystem.c @@ -24,14 +24,13 @@ */ #include "driver-config.h" -#include "compat_kernel.h" +#include #include #include #include -#include "compat_fs.h" -#include "compat_spinlock.h" +#include + #include "compat_namei.h" -#include "compat_slab.h" #include "os.h" #include "vmblockInt.h" @@ -40,30 +39,17 @@ #define VMBLOCK_ROOT_INO 1 #define GetRootInode(sb) Iget(sb, NULL, NULL, VMBLOCK_ROOT_INO) -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 25) -# define KERNEL_25_FS 0 -#else -# define KERNEL_25_FS 1 -#endif - static struct inode *GetInode(struct super_block *sb, ino_t ino); /* File system operations */ -#if KERNEL_25_FS /* { */ -# if defined(VMW_GETSB_2618) + +#if defined(VMW_GETSB_2618) static int FsOpGetSb(struct file_system_type *fsType, int flags, const char *devName, void *rawData, struct vfsmount *mnt); -# elif LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 70) +#else static struct super_block *FsOpGetSb(struct file_system_type *fsType, int flags, const char *devName, void *rawData); -# else -static struct super_block *FsOpGetSb(struct file_system_type *fsType, int flags, - char *devName, void *rawData); -# endif -#else /* } { */ -static struct super_block *FsOpReadSuper24(struct super_block *sb, void *rawData, - int flags); -#endif /* } */ +#endif static int FsOpReadSuper(struct super_block *sb, void *rawData, int flags); @@ -80,12 +66,8 @@ static size_t fsRootLen; static struct file_system_type fsType = { .owner = THIS_MODULE, .name = VMBLOCK_FS_NAME, -#if KERNEL_25_FS .get_sb = FsOpGetSb, .kill_sb = kill_anon_super, -#else - .read_super = FsOpReadSuper24, -#endif }; @@ -239,16 +221,9 @@ VMBlockReadInode(struct inode *inode) // IN: Inode to initialize ino_t GetNextIno(void) { - static spinlock_t inoLock = SPIN_LOCK_UNLOCKED; - static ino_t nextIno = VMBLOCK_ROOT_INO + 1; - ino_t ret; + static atomic_t nextIno = ATOMIC_INIT(VMBLOCK_ROOT_INO + 1); - /* Too bad atomic_t's don't provide an atomic increment and read ... */ - spin_lock(&inoLock); - ret = nextIno++; - spin_unlock(&inoLock); - - return ret; + return (ino_t) atomic_inc_return(&nextIno); } @@ -277,7 +252,6 @@ static struct inode * GetInode(struct super_block *sb, // IN: file system superblock object ino_t ino) // IN: inode number to assign to new inode { -#ifdef VMW_USE_IGET_LOCKED struct inode *inode; inode = iget_locked(sb, ino); @@ -288,9 +262,6 @@ GetInode(struct super_block *sb, // IN: file system superblock object unlock_new_inode(inode); } return inode; -#else - return iget(sb, ino); -#endif } @@ -414,11 +385,9 @@ error_inode: static void InodeCacheCtor(COMPAT_KMEM_CACHE_CTOR_ARGS(slabElem)) // IN: allocated slab item to initialize { -#ifdef VMW_EMBED_INODE VMBlockInodeInfo *iinfo = slabElem; inode_init_once(&iinfo->inode); -#endif } @@ -460,6 +429,7 @@ MakeFullName(struct inode *dir, // IN : directory bufOut[fsRootLen] = '\0'; } else { VMBlockInodeInfo *dirIinfo; + int ret; ASSERT(dir); ASSERT(dentry); @@ -470,47 +440,18 @@ MakeFullName(struct inode *dir, // IN : directory } dirIinfo = INODE_TO_IINFO(dir); + /* * If dirIinfo->name[1] is '\0', then it is "/" and we don't need * another '/' between it and the additional name. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 10) - { - int ret; - - ret = snprintf(bufOut, bufOutSize, - dirIinfo->name[1] == '\0' ? "%s%s" : "%s/%s", - dirIinfo->name, dentry->d_name.name); - if (ret >= bufOutSize) { - Warning("MakeFullName: path was too long.\n"); - return -ENAMETOOLONG; - } - } -#else - { - /* snprintf was not exported prior to 2.4.10 */ - size_t dirLen; - size_t pathSepLen; - size_t dentryLen; - size_t pathLen; - - dirLen = strlen(dirIinfo->name); - pathSepLen = dirLen == 1 ? 0 : 1; - dentryLen = strlen(dentry->d_name.name); - pathLen = dirLen + dentryLen + pathSepLen; - if (pathLen >= bufOutSize) { - Warning("MakeFullName: path was too long.\n"); - return -ENAMETOOLONG; - } - memcpy(bufOut, dirIinfo->name, dirLen); - if (pathSepLen == 1) { - ASSERT(dirLen == 1); - bufOut[dirLen] = '/'; - } - memcpy(bufOut + dirLen + pathSepLen, dentry->d_name.name, dentryLen); - bufOut[pathLen] = '\0'; + ret = snprintf(bufOut, bufOutSize, + dirIinfo->name[1] == '\0' ? "%s%s" : "%s/%s", + dirIinfo->name, dentry->d_name.name); + if (ret >= bufOutSize) { + Warning("MakeFullName: path was too long.\n"); + return -ENAMETOOLONG; } -#endif } return 0; @@ -593,7 +534,6 @@ FsOpReadSuper(struct super_block *sb, // OUT: Superblock object } -#if KERNEL_25_FS /* { */ #if defined(VMW_GETSB_2618) /* *----------------------------------------------------------------------------- @@ -641,48 +581,13 @@ FsOpGetSb(struct file_system_type *fs_type, // IN: file system type of mount *----------------------------------------------------------------------------- */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 70) static struct super_block * FsOpGetSb(struct file_system_type *fs_type, // IN: file system type of mount int flags, // IN: mount flags const char *dev_name, // IN: device mounting on void *rawData) // IN: mount arguments -#else -static struct super_block * -FsOpGetSb(struct file_system_type *fs_type, // IN: file system type of mount - int flags, // IN: mount flags - char *dev_name, // IN: device mounting on - void *rawData) // IN: mount arguments -#endif { return get_sb_nodev(fs_type, flags, rawData, FsOpReadSuper); } #endif -#else /* } { */ - -/* - *----------------------------------------------------------------------------- - * - * FsOpReadSuper24 -- - * - * Compatibility wrapper for 2.4.x kernels read_super. - * Converts success to sb, and failure to NULL. - * - * Results: - * The initialized superblock on success - * NULL on failure - * - * Side effects: - * None - * - *----------------------------------------------------------------------------- - */ -static struct super_block * -FsOpReadSuper24(struct super_block *sb, // OUT: Superblock object - void *rawData, // IN : mount arguments - int flags) // IN : mount flags -{ - return FsOpReadSuper(sb, rawData, flags) ? NULL : sb; -} -#endif /* } */ diff --git a/open-vm-tools/modules/linux/vmblock/linux/filesystem.h b/open-vm-tools/modules/linux/vmblock/linux/filesystem.h index 2f39702d2..e4772fcf9 100644 --- a/open-vm-tools/modules/linux/vmblock/linux/filesystem.h +++ b/open-vm-tools/modules/linux/vmblock/linux/filesystem.h @@ -47,33 +47,11 @@ #define __FILESYSTEM_H__ #include "compat_slab.h" -#include "compat_fs.h" +#include #include "vm_basic_types.h" -#ifndef container_of -#define container_of(ptr, type, memb) ((type *)((char *)(ptr) - offsetof(type, memb))) -#endif - -#ifdef VMW_EMBED_INODE -# define INODE_SET_IINFO(inode, iinfo) -# define INODE_TO_IINFO(_inode) container_of(_inode, VMBlockInodeInfo, inode) -#else -# define INODE_SET_IINFO(inode, iinfo) (inode)->u.generic_ip = iinfo -# define INODE_TO_IINFO(_inode) \ - ({ \ - /* Allocate an inode info for new inodes */ \ - if ((_inode)->u.generic_ip == NULL) { \ - VMBlockInodeInfo *_iinfo; \ - ASSERT(VMBlockInodeCache); \ - _iinfo = kmem_cache_alloc(VMBlockInodeCache, SLAB_KERNEL); \ - /* We must set the inode info for new inodes */ \ - INODE_SET_IINFO(_inode, _iinfo); \ - } \ - ((VMBlockInodeInfo *)((_inode)->u.generic_ip)); \ - }) -#endif - +#define INODE_TO_IINFO(_inode) container_of(_inode, VMBlockInodeInfo, inode) #define INODE_TO_ACTUALDENTRY(inode) INODE_TO_IINFO(inode)->actualDentry #define INODE_TO_ACTUALINODE(inode) INODE_TO_IINFO(inode)->actualDentry->d_inode @@ -83,10 +61,8 @@ typedef struct VMBlockInodeInfo { char name[PATH_MAX]; size_t nameLen; struct dentry *actualDentry; -#ifdef VMW_EMBED_INODE /* Embedded inode */ struct inode inode; -#endif } VMBlockInodeInfo; diff --git a/open-vm-tools/modules/linux/vmblock/linux/inode.c b/open-vm-tools/modules/linux/vmblock/linux/inode.c index d27dc28b4..098c94c8c 100644 --- a/open-vm-tools/modules/linux/vmblock/linux/inode.c +++ b/open-vm-tools/modules/linux/vmblock/linux/inode.c @@ -25,11 +25,9 @@ #include "driver-config.h" #include -#include "compat_fs.h" +#include #include -#include "compat_namei.h" -#include "compat_uaccess.h" -#include "compat_sched.h" +#include #include "vmblockInt.h" #include "filesystem.h" @@ -37,12 +35,8 @@ /* Inode operations */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75) static struct dentry *InodeOpLookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd); -#else -static struct dentry *InodeOpLookup(struct inode *dir, struct dentry *dentry); -#endif static int InodeOpReadlink(struct dentry *dentry, char __user *buffer, int buflen); #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 13) static void *InodeOpFollowlink(struct dentry *dentry, struct nameidata *nd); @@ -78,16 +72,10 @@ static struct inode_operations LinkInodeOps = { *---------------------------------------------------------------------------- */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 75) static struct dentry * InodeOpLookup(struct inode *dir, // IN: parent directory's inode struct dentry *dentry, // IN: dentry to lookup struct nameidata *nd) // IN: lookup intent and information -#else -static struct dentry * -InodeOpLookup(struct inode *dir, // IN: parent directory's inode - struct dentry *dentry) // IN: dentry to lookup -#endif { char *filename; struct inode *inode; @@ -105,7 +93,7 @@ InodeOpLookup(struct inode *dir, // IN: parent directory's inode } /* Get a slab from the kernel's names_cache of PATH_MAX-sized buffers. */ - filename = compat___getname(); + filename = __getname(); if (!filename) { Warning("InodeOpLookup: unable to obtain memory for filename.\n"); return ERR_PTR(-ENOMEM); @@ -114,13 +102,13 @@ InodeOpLookup(struct inode *dir, // IN: parent directory's inode ret = MakeFullName(dir, dentry, filename, PATH_MAX); if (ret < 0) { Warning("InodeOpLookup: could not construct full name\n"); - compat___putname(filename); + __putname(filename); return ERR_PTR(ret); } /* Block if there is a pending block on this file */ BlockWaitOnFile(filename, NULL); - compat___putname(filename); + __putname(filename); inode = Iget(dir->i_sb, dir, dentry, GetNextIno()); if (!inode) { diff --git a/open-vm-tools/modules/linux/vmblock/linux/module.c b/open-vm-tools/modules/linux/vmblock/linux/module.c index c24f2efc1..bb33165d4 100644 --- a/open-vm-tools/modules/linux/vmblock/linux/module.c +++ b/open-vm-tools/modules/linux/vmblock/linux/module.c @@ -24,12 +24,10 @@ */ #include "driver-config.h" -#include "compat_init.h" -#include "compat_kernel.h" -#include "compat_module.h" +#include +#include #include #include -#include "compat_string.h" #include "vmblockInt.h" #include "vmblock_version.h" @@ -37,21 +35,13 @@ /* Module parameters */ #ifdef VMX86_DEVEL /* { */ int LOGLEVEL_THRESHOLD = 4; -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) - module_param(LOGLEVEL_THRESHOLD, int, 0600); -# else - MODULE_PARM(LOGLEVEL_THRESHOLD, "i"); -# endif +module_param(LOGLEVEL_THRESHOLD, int, 0600); MODULE_PARM_DESC(LOGLEVEL_THRESHOLD, "Logging level (0 means no log, " "10 means very verbose, 4 is default)"); #endif /* } */ static char *root = "/tmp/VMwareDnD"; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) module_param(root, charp, 0600); -#else -MODULE_PARM(root, "s"); -#endif MODULE_PARM_DESC(root, "The directory the file system redirects to."); /* Module information */ @@ -67,15 +57,6 @@ MODULE_VERSION(VMBLOCK_DRIVER_VERSION_STRING); */ MODULE_INFO(supported, "external"); -/* Functions */ -static int VMBlockInit(void); -static void VMBlockExit(void); - -/* Define init/exit routines */ -module_init(VMBlockInit); -module_exit(VMBlockExit); - - /* *---------------------------------------------------------------------------- * @@ -117,6 +98,8 @@ error: return ret; } +module_init(VMBlockInit); + /* *---------------------------------------------------------------------------- @@ -144,39 +127,4 @@ VMBlockExit(void) LOG(4, "module unloaded\n"); } - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 70) -/* - *---------------------------------------------------------------------------- - * - * strlcpy -- - * - * 2.4 doesn't have strlcpy(). - * - * Copies at most count - 1 bytes from src to dest, and ensures dest is NUL - * terminated. - * - * Results: - * Length of src. If src >= count, src was truncated in copy. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -size_t -strlcpy(char *dest, // OUT: destination to copy string to - const char *src, // IN : source to copy string from - size_t count) // IN : size of destination buffer -{ - size_t ret; - size_t len; - - ret = strlen(src); - len = ret >= count ? count - 1 : ret; - memcpy(dest, src, len); - dest[len] = '\0'; - return ret; -} -#endif +module_exit(VMBlockExit); diff --git a/open-vm-tools/modules/linux/vmblock/linux/os.h b/open-vm-tools/modules/linux/vmblock/linux/os.h index eaeb44f0e..f592e17e5 100644 --- a/open-vm-tools/modules/linux/vmblock/linux/os.h +++ b/open-vm-tools/modules/linux/vmblock/linux/os.h @@ -28,21 +28,17 @@ #define __OS_H__ #include "driver-config.h" -#include "compat_list.h" -#include "compat_completion.h" +#include #include #include "compat_slab.h" -#include "compat_wait.h" +#include #include #include -#include "compat_sched.h" #include -#include "compat_kernel.h" -#include "compat_spinlock.h" typedef rwlock_t os_rwlock_t; typedef compat_kmem_cache os_kmem_cache_t; -typedef compat_completion os_completion_t; +typedef struct completion os_completion_t; typedef atomic_t os_atomic_t; typedef struct file * os_blocker_id_t; @@ -54,22 +50,12 @@ typedef struct file * os_blocker_id_t; #define OS_FMTTID "d" #define os_threadid (current->pid) -/* - * XXX vprintk() wasn't exported until 2.6.9; we should do something more - * intelligent here eventually. - */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) -# define os_panic(fmt, args) \ + +#define os_panic(fmt, args) \ ({ \ vprintk(fmt, args); \ BUG(); \ }) -#else -# define os_panic(fmt, args) \ - ({ \ - BUG(); \ - }) -#endif #define os_rwlock_init(lock) rwlock_init(lock) #define os_rwlock_destroy(lock) @@ -94,7 +80,7 @@ typedef struct file * os_blocker_id_t; #define os_kmem_cache_alloc(cache) kmem_cache_alloc(cache, GFP_KERNEL) #define os_kmem_cache_free(cache, elem) kmem_cache_free(cache, elem) -#define os_completion_init(comp) compat_init_completion(comp) +#define os_completion_init(comp) init_completion(comp) #define os_completion_destroy(comp) /* * XXX This should be made interruptible using @@ -103,10 +89,10 @@ typedef struct file * os_blocker_id_t; */ #define os_wait_for_completion(comp) \ ({ \ - compat_wait_for_completion(comp); \ + wait_for_completion(comp); \ 0; \ }) -#define os_complete_all(comp) compat_complete_all(comp) +#define os_complete_all(comp) complete_all(comp) #define os_atomic_dec_and_test(atomic) atomic_dec_and_test(atomic) #define os_atomic_dec(atomic) atomic_dec(atomic) diff --git a/open-vm-tools/modules/linux/vmblock/linux/super.c b/open-vm-tools/modules/linux/vmblock/linux/super.c index 79e2e4a90..fb65c578c 100644 --- a/open-vm-tools/modules/linux/vmblock/linux/super.c +++ b/open-vm-tools/modules/linux/vmblock/linux/super.c @@ -24,44 +24,29 @@ */ #include "driver-config.h" -#include "compat_fs.h" -#include "compat_statfs.h" +#include +#include #include "vmblockInt.h" #include "filesystem.h" /* Super block operations */ -#ifdef VMW_EMBED_INODE static struct inode *SuperOpAllocInode(struct super_block *sb); static void SuperOpDestroyInode(struct inode *inode); -#else -static void SuperOpClearInode(struct inode *inode); -#endif -#ifndef VMW_USE_IGET_LOCKED -static void SuperOpReadInode(struct inode *inode); -#endif #ifdef VMW_STATFS_2618 -static int SuperOpStatfs(struct dentry *dentry, struct compat_kstatfs *stat); +static int SuperOpStatfs(struct dentry *dentry, struct kstatfs *stat); #else -static int SuperOpStatfs(struct super_block *sb, struct compat_kstatfs *stat); +static int SuperOpStatfs(struct super_block *sb, struct kstatfs *stat); #endif struct super_operations VMBlockSuperOps = { -#ifdef VMW_EMBED_INODE .alloc_inode = SuperOpAllocInode, .destroy_inode = SuperOpDestroyInode, -#else - .clear_inode = SuperOpClearInode, -#endif -#ifndef VMW_USE_IGET_LOCKED - .read_inode = SuperOpReadInode, -#endif .statfs = SuperOpStatfs, }; -#ifdef VMW_EMBED_INODE /* *---------------------------------------------------------------------------- * @@ -93,7 +78,6 @@ SuperOpAllocInode(struct super_block *sb) // IN: superblock of file system /* The inode we give back to VFS is embedded within our inode info struct. */ return &iinfo->inode; } -#endif /* @@ -116,43 +100,12 @@ SuperOpAllocInode(struct super_block *sb) // IN: superblock of file system */ static void -#ifdef VMW_EMBED_INODE SuperOpDestroyInode(struct inode *inode) // IN: Inode to free -#else -SuperOpClearInode(struct inode *inode) // IN: Inode to free -#endif { kmem_cache_free(VMBlockInodeCache, INODE_TO_IINFO(inode)); } -#ifndef VMW_USE_IGET_LOCKED -/* - *---------------------------------------------------------------------------- - * - * SuperOpReadInode -- - * - * Performs any filesystem wide inode initialization. This is only called by - * iget() in older kernels that do not support iget_locked(). Newer kernels - * that use the iget_locked() interface are required to initialize the inode - * after it has been returned to the filesystem. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -static void -SuperOpReadInode(struct inode *inode) // IN: Inode to initialize -{ - VMBlockReadInode(inode); -} -#endif - /* *---------------------------------------------------------------------------- * @@ -172,11 +125,11 @@ SuperOpReadInode(struct inode *inode) // IN: Inode to initialize #ifdef VMW_STATFS_2618 static int SuperOpStatfs(struct dentry *dentry, - struct compat_kstatfs *stat) + struct kstatfs *stat) #else static int SuperOpStatfs(struct super_block *sb, - struct compat_kstatfs *stat) + struct kstatfs *stat) #endif { if (!stat) { diff --git a/open-vm-tools/modules/linux/vmblock/linux/vmblockInt.h b/open-vm-tools/modules/linux/vmblock/linux/vmblockInt.h index db8e420e0..76cc4a165 100644 --- a/open-vm-tools/modules/linux/vmblock/linux/vmblockInt.h +++ b/open-vm-tools/modules/linux/vmblock/linux/vmblockInt.h @@ -33,8 +33,8 @@ #ifndef __VMBLOCKINT_H__ #define __VMBLOCKINT_H__ -#include "compat_version.h" -#include "compat_mm.h" +#include +#include #include "vmblock.h" #include "vm_basic_types.h" @@ -73,9 +73,7 @@ extern int LOGLEVEL_THRESHOLD; * * XXX This should go in driver-config.h, but vmmon's hostKernel.h is retarded. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 3, 29) static const void *forceProcessorCheck __attribute__((unused)) = __alloc_pages; -#endif /* @@ -87,8 +85,4 @@ int VMBlockCleanupControlOps(void); int VMBlockInitFileSystem(char const *root); int VMBlockCleanupFileSystem(void); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 70) -size_t strlcpy(char *dest, const char *src, size_t count); -#endif - #endif /* __VMBLOCK_H__ */ diff --git a/open-vm-tools/modules/linux/vmci/vmciGuestKernelIf.c b/open-vm-tools/modules/linux/vmci/vmciGuestKernelIf.c index d9e5cd14f..f57b0eb80 100644 --- a/open-vm-tools/modules/linux/vmci/vmciGuestKernelIf.c +++ b/open-vm-tools/modules/linux/vmci/vmciGuestKernelIf.c @@ -17,11 +17,11 @@ *********************************************************/ /* - * vmciGuestKernelIf.c -- - * + * vmciGuestKernelIf.c -- + * * This file implements guest only OS helper functions for VMCI. * This is the linux specific implementation. - */ + */ /* Must come before any kernel header file */ #include "driver-config.h" @@ -30,9 +30,7 @@ #error "Wrong platform." #endif -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) #include -#endif #include "compat_version.h" #include "compat_pci.h" diff --git a/open-vm-tools/modules/linux/vmci/vmciKernelIf.c b/open-vm-tools/modules/linux/vmci/vmciKernelIf.c index cc2de6acc..1bd87968f 100644 --- a/open-vm-tools/modules/linux/vmci/vmciKernelIf.c +++ b/open-vm-tools/modules/linux/vmci/vmciKernelIf.c @@ -31,6 +31,10 @@ #error "Wrong platform." #endif +#if !defined(VMX86_TOOLS) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) +# error "Host Linux kernels before 2.6.9 are not supported." +#endif + #define EXPORT_SYMTAB #define __NO_VERSION__ #include "compat_module.h" @@ -1416,7 +1420,6 @@ VMCIHost_GetUserMemory(PageStoreAttachInfo *attach, // IN/OUT VMCIQueue *produceQ, // OUT VMCIQueue *consumeQ) // OUT { -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) int retval; int err = VMCI_SUCCESS; @@ -1501,70 +1504,6 @@ errorDealloc: } return err; - -#else - /* - * Host queue pair support for earlier kernels temporarily - * disabled. See bug 365496. - */ - - ASSERT_NOT_IMPLEMENTED(FALSE); -#if 0 - attach->produceIoBuf = VMCI_AllocKernelMem(sizeof *attach->produceIoBuf, - VMCI_MEMORY_NORMAL); - if (attach->produceIoBuf == NULL) { - return VMCI_ERROR_NO_MEM; - } - - attach->consumeIoBuf = VMCI_AllocKernelMem(sizeof *attach->consumeIoBuf, - VMCI_MEMORY_NORMAL); - if (attach->consumeIoBuf == NULL) { - VMCI_FreeKernelMem(attach->produceIoBuf, - sizeof *attach->produceIoBuf); - return VMCI_ERROR_NO_MEM; - } - - retval = map_user_kiobuf(WRITE, attach->produceIoBuf, - (VA)attach->produceBuffer, - attach->numProducePages * PAGE_SIZE); - if (retval < 0) { - err = VMCI_ERROR_NO_ACCESS; - goto out; - } - - retval = map_user_kiobuf(WRITE, attach->consumeIoBuf, - (VA)attach->consumeBuffer, - attach->numConsumePages * PAGE_SIZE); - if (retval < 0) { - unmap_kiobuf(attach->produceIoBuf); - err = VMCI_ERROR_NO_ACCESS; - } - - if (err == VMCI_SUCCESS) { - produceQ->queueHeaderPtr = kmap(attach->produceIoBuf->maplist[0]); - produceQ->page = &attach->produceIoBuf->maplist[1]; - consumeQ->queueHeaderPtr = kmap(attach->consumeIoBuf->maplist[0]); - consumeQ->page = &attach->consumeIoBuf->maplist[1]; - } - -out: - - if (err < VMCI_SUCCESS) { - if (attach->produceIoBuf != NULL) { - VMCI_FreeKernelMem(attach->produceIoBuf, - sizeof *attach->produceIoBuf); - } - if (attach->consumeIoBuf != NULL) { - VMCI_FreeKernelMem(attach->consumeIoBuf, - sizeof *attach->consumeIoBuf); - } - } - - return err; -#else // 0 -- Instead just return FALSE - return FALSE; -#endif // 0 -#endif // Linux version >= 2.6.0 } @@ -1590,8 +1529,6 @@ VMCIHost_ReleaseUserMemory(PageStoreAttachInfo *attach, // IN/OUT VMCIQueue *produceQ, // OUT VMCIQueue *consumeQ) // OUT { - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0) int i; ASSERT(attach->producePages); @@ -1620,31 +1557,6 @@ VMCIHost_ReleaseUserMemory(PageStoreAttachInfo *attach, // IN/OUT VMCI_FreeKernelMem(attach->consumePages, attach->numConsumePages * sizeof attach->consumePages[0]); -#else - /* - * Host queue pair support for earlier kernels temporarily - * disabled. See bug 365496. - */ - - ASSERT_NOT_IMPLEMENTED(FALSE); -#if 0 - kunmap(attach->produceIoBuf->maplist[0]); - kunmap(attach->consumeIoBuf->maplist[0]); - - mark_dirty_kiobuf(attach->produceIoBuf, - attach->numProducePages * PAGE_SIZE); - unmap_kiobuf(attach->produceIoBuf); - - mark_dirty_kiobuf(attach->consumeIoBuf, - attach->numConsumePages * PAGE_SIZE); - unmap_kiobuf(attach->consumeIoBuf); - - VMCI_FreeKernelMem(attach->produceIoBuf, - sizeof *attach->produceIoBuf); - VMCI_FreeKernelMem(attach->consumeIoBuf, - sizeof *attach->consumeIoBuf); -#endif -#endif } -#endif +#endif /* Host only code */ diff --git a/open-vm-tools/modules/linux/vmci/vmci_drv.c b/open-vm-tools/modules/linux/vmci/vmci_drv.c index ac64f024f..e487ecbd2 100644 --- a/open-vm-tools/modules/linux/vmci/vmci_drv.c +++ b/open-vm-tools/modules/linux/vmci/vmci_drv.c @@ -16,21 +16,16 @@ * *********************************************************/ -/* +/* * vmci.c -- * * Linux guest driver for the VMCI device. */ - + #include "driver-config.h" -#define EXPORT_SYMTAB - - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) #include -#endif - + #include "compat_kernel.h" #include "compat_module.h" #include "compat_pci.h" @@ -73,11 +68,11 @@ static int vmci_probe_device(struct pci_dev *pdev, static void vmci_remove_device(struct pci_dev* pdev); static int vmci_open(struct inode *inode, struct file *file); static int vmci_close(struct inode *inode, struct file *file); -static int vmci_ioctl(struct inode *inode, struct file *file, +static int vmci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg); static unsigned int vmci_poll(struct file *file, poll_table *wait); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19) -static compat_irqreturn_t vmci_interrupt(int irq, void *dev_id, +static compat_irqreturn_t vmci_interrupt(int irq, void *dev_id, struct pt_regs * regs); #else static compat_irqreturn_t vmci_interrupt(int irq, void *dev_id); @@ -109,15 +104,15 @@ static vmci_device vmci_dev; /* We dynamically request the device major number at init time. */ static int device_major_nr = 0; -DECLARE_TASKLET(vmci_tasklet, dispatch_datagrams, +DECLARE_TASKLET(vmci_tasklet, dispatch_datagrams, (unsigned long)&vmci_dev); -/* - * Allocate a buffer for incoming datagrams globally to avoid repeated - * allocation in the interrupt handler's atomic context. - */ +/* + * Allocate a buffer for incoming datagrams globally to avoid repeated + * allocation in the interrupt handler's atomic context. + */ -static uint8 *data_buffer = NULL; +static uint8 *data_buffer = NULL; static uint32 data_buffer_size = VMCI_MAX_DG_SIZE; @@ -145,7 +140,7 @@ vmci_init(void) /* Register device node ops. */ err = register_chrdev(0, "vmci", &vmci_ops); if (err < 0) { - printk(KERN_ERR "Unable to register vmci device\n"); + printk(KERN_ERR "Unable to register vmci device\n"); return err; } device_major_nr = err; @@ -161,7 +156,7 @@ vmci_init(void) if (data_buffer == NULL) { goto error; } - + /* This should be last to make sure we are done initializing. */ err = pci_register_driver(&vmci_driver); if (err < 0) { @@ -197,7 +192,7 @@ static void vmci_exit(void) { pci_unregister_driver(&vmci_driver); - + unregister_chrdev(device_major_nr, "vmci"); vfree(data_buffer); @@ -293,7 +288,7 @@ vmci_probe_device(struct pci_dev *pdev, // IN: vmci PCI device vmci_dev.enabled = TRUE; pci_set_drvdata(pdev, &vmci_dev); - /* + /* * We do global initialization here because we need datagrams for * event init. If we ever support more than one VMCI device we will * have to create seperate LateInit/EarlyExit functions that can be @@ -309,7 +304,7 @@ vmci_probe_device(struct pci_dev *pdev, // IN: vmci PCI device VMCIUtil_Init(); VMCIQueuePair_Init(); - if (request_irq(vmci_dev.irq, vmci_interrupt, COMPAT_IRQF_SHARED, + if (request_irq(vmci_dev.irq, vmci_interrupt, COMPAT_IRQF_SHARED, "vmci", &vmci_dev)) { printk(KERN_ERR "vmci: irq %u in use\n", vmci_dev.irq); goto components_exit; @@ -372,7 +367,7 @@ vmci_remove_device(struct pci_dev* pdev) VMCIEvent_Exit(); //VMCIDatagram_Exit(); VMCIProcess_Exit(); - + down(&dev->lock); printk(KERN_INFO "Resetting vmci device\n"); outl(VMCI_CONTROL_RESET, vmci_dev.ioaddr + VMCI_CONTROL_ADDR); @@ -382,7 +377,7 @@ vmci_remove_device(struct pci_dev* pdev) printk(KERN_INFO "Unregistered vmci device.\n"); up(&dev->lock); - + compat_pci_disable_device(pdev); } @@ -549,7 +544,7 @@ vmci_ioctl(struct inode *inode, // IN retval = -EFAULT; break; } - + if (VMCIDatagramProcess_Create(&dgmProc, &createInfo, 0 /* Unused */) < VMCI_SUCCESS) { retval = -EINVAL; @@ -608,8 +603,8 @@ vmci_ioctl(struct inode *inode, // IN } DEBUG_ONLY(printk("VMCI: Datagram dst handle 0x%x:0x%x, src handle " - "0x%x:0x%x, payload size %"FMT64"u.\n", - dg->dst.context, dg->dst.resource, + "0x%x:0x%x, payload size %"FMT64"u.\n", + dg->dst.context, dg->dst.resource, dg->src.context, dg->src.resource, dg->payloadSize)); sendInfo.result = VMCIDatagram_Send(dg); @@ -638,8 +633,8 @@ vmci_ioctl(struct inode *inode, // IN } ASSERT(devHndl->obj); - recvInfo.result = - VMCIDatagramProcess_ReadCall((VMCIDatagramProcess *)devHndl->obj, + recvInfo.result = + VMCIDatagramProcess_ReadCall((VMCIDatagramProcess *)devHndl->obj, recvInfo.len, &dg); if (recvInfo.result < VMCI_SUCCESS) { retval = -EINVAL; @@ -699,17 +694,17 @@ vmci_poll(struct file *file, // IN VMCIGuestDeviceHandle *devHndl = (VMCIGuestDeviceHandle *) file->private_data; - /* - * Check for call to this VMCI process. + /* + * Check for call to this VMCI process. */ - + if (!devHndl) { return mask; } if (devHndl->objType == VMCIOBJ_DATAGRAM_PROCESS) { VMCIDatagramProcess *dgmProc = (VMCIDatagramProcess *) devHndl->obj; ASSERT(dgmProc); - + if (wait != NULL) { poll_wait(file, &dgmProc->host.waitQueue, wait); } @@ -803,7 +798,7 @@ VMCI_DeviceEnabled(void) down(&vmci_dev.lock); retval = vmci_dev.enabled; up(&vmci_dev.lock); - + return retval; } @@ -846,7 +841,7 @@ VMCI_SendDatagram(VMCIDatagram *dg) */ spin_lock_irqsave(&vmci_dev.dev_spinlock, flags); - /* + /* * Send the datagram and retrieve the return value from the result register. */ __asm__ __volatile__( @@ -894,7 +889,7 @@ dispatch_datagrams(unsigned long data) "present.\n"); return; } - + if (data_buffer == NULL) { printk(KERN_DEBUG "vmci: dispatch_datagrams(): no buffer present.\n"); return; diff --git a/open-vm-tools/modules/linux/vmci/vmci_version.h b/open-vm-tools/modules/linux/vmci/vmci_version.h index e92477f3c..01b6cf44f 100644 --- a/open-vm-tools/modules/linux/vmci/vmci_version.h +++ b/open-vm-tools/modules/linux/vmci/vmci_version.h @@ -25,8 +25,8 @@ #ifndef _VMCI_VERSION_H_ #define _VMCI_VERSION_H_ -#define VMCI_DRIVER_VERSION 1.0.18.0 -#define VMCI_DRIVER_VERSION_COMMAS 1,0,18,0 -#define VMCI_DRIVER_VERSION_STRING "1.0.18.0" +#define VMCI_DRIVER_VERSION 1.0.19.0 +#define VMCI_DRIVER_VERSION_COMMAS 1,0,19,0 +#define VMCI_DRIVER_VERSION_STRING "1.0.19.0" #endif /* _VMCI_VERSION_H_ */ diff --git a/open-vm-tools/modules/linux/vmhgfs/dir.c b/open-vm-tools/modules/linux/vmhgfs/dir.c index 18e52c82c..7865e13f6 100644 --- a/open-vm-tools/modules/linux/vmhgfs/dir.c +++ b/open-vm-tools/modules/linux/vmhgfs/dir.c @@ -43,15 +43,17 @@ /* Private functions. */ static int HgfsUnpackSearchReadReply(HgfsReq *req, - HgfsAttrInfo *attr); + HgfsAttrInfo *attr, + char **entryName); static int HgfsGetNextDirEntry(HgfsSuperInfo *si, HgfsHandle searchHandle, uint32 offset, HgfsAttrInfo *attr, + char **entryName, Bool *done); static int HgfsPackDirOpenRequest(struct inode *inode, struct file *file, - HgfsOp opUsed, + HgfsOp opUsed, HgfsReq *req); /* HGFS file operations for directories. */ @@ -98,7 +100,8 @@ struct file_operations HgfsDirFileOperations = { */ static int HgfsUnpackSearchReadReply(HgfsReq *req, // IN: Reply packet - HgfsAttrInfo *attr) // IN/OUT: Attributes + HgfsAttrInfo *attr, // IN/OUT: Attributes + char **entryName) // OUT: file name { char *fileName; uint32 fileNameLength; @@ -175,15 +178,15 @@ HgfsUnpackSearchReadReply(HgfsReq *req, // IN: Reply packet fileNameLength, strlen(fileName), fileName)); return -EPROTO; } - attr->fileName = kmalloc(fileNameLength + 1, GFP_KERNEL); - if (attr->fileName == NULL) { + *entryName = kmalloc(fileNameLength + 1, GFP_KERNEL); + if (*entryName == NULL) { LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackSearchReadReply: out of " "memory allocating filename, ignoring\n")); return -ENOMEM; } - memcpy(attr->fileName, fileName, fileNameLength + 1); + memcpy(*entryName, fileName, fileNameLength + 1); } else { - attr->fileName = NULL; + *entryName = NULL; } return 0; } @@ -196,7 +199,7 @@ HgfsUnpackSearchReadReply(HgfsReq *req, // IN: Reply packet * * Get the directory entry with the given offset from the server. * - * attr->fileName gets allocated and must be freed by the caller. + * fileName gets allocated and must be freed by the caller. * * Results: * Returns zero on success, negative error on failure. If the @@ -213,6 +216,7 @@ HgfsGetNextDirEntry(HgfsSuperInfo *si, // IN: Superinfo for this SB HgfsHandle searchHandle, // IN: Handle of dir uint32 offset, // IN: Offset of next dentry to get HgfsAttrInfo *attr, // OUT: File attributes of dentry + char **entryName, // OUT: File name Bool *done) // OUT: Set true when there are // no more dentries { @@ -268,8 +272,8 @@ HgfsGetNextDirEntry(HgfsSuperInfo *si, // IN: Superinfo for this SB switch(result) { case 0: - result = HgfsUnpackSearchReadReply(req, attr); - if (result == 0 && attr->fileName == NULL) { + result = HgfsUnpackSearchReadReply(req, attr, entryName); + if (result == 0 && *entryName == NULL) { /* We're at the end of the directory. */ LOG(6, (KERN_DEBUG "VMware hgfs: HgfsGetNextDirEntry: end of " "dir\n")); @@ -573,6 +577,7 @@ HgfsReaddir(struct file *file, // IN: Directory to read from HgfsSuperInfo *si; HgfsAttrInfo attr; uint32 d_type; // type of dirent + char *fileName = NULL; char *escName = NULL; // buf for escaped version of name size_t escNameLength = NAME_MAX + 1; int nameLength = 0; @@ -616,13 +621,14 @@ HgfsReaddir(struct file *file, // IN: Directory to read from * Nonzero result = we failed to get valid reply from server. * Zero result: * - done == TRUE means we hit the end of the directory - * - Otherwise, attr.fileName has the name of the next dirent + * - Otherwise, fileName has the name of the next dirent * */ result = HgfsGetNextDirEntry(si, FILE_GET_FI_P(file)->handle, (uint32)file->f_pos, &attr, + &fileName, &done); if (result == -ENAMETOOLONG) { /* @@ -654,11 +660,10 @@ HgfsReaddir(struct file *file, // IN: Directory to read from * CP name format, but that is done implicitely here since we * are guaranteed to have just one path component per dentry. */ - result = HgfsEscape_Do(attr.fileName, - strlen(attr.fileName), - escNameLength, - escName); - kfree(attr.fileName); + result = HgfsEscape_Do(fileName, strlen(fileName), + escNameLength, escName); + kfree(fileName); + fileName = NULL; /* * Check the filename length. diff --git a/open-vm-tools/modules/linux/vmhgfs/fsutil.c b/open-vm-tools/modules/linux/vmhgfs/fsutil.c index 3c69efdcb..8d28b79c9 100644 --- a/open-vm-tools/modules/linux/vmhgfs/fsutil.c +++ b/open-vm-tools/modules/linux/vmhgfs/fsutil.c @@ -52,7 +52,8 @@ static struct inode *HgfsInodeLookup(struct super_block *sb, static void HgfsSetFileType(struct inode *inode, HgfsAttrInfo const *attr); static int HgfsUnpackGetattrReply(HgfsReq *req, - HgfsAttrInfo *attr); + HgfsAttrInfo *attr, + char **fileName); static int HgfsPackGetattrRequest(HgfsReq *req, struct dentry *dentry, Bool allowHandleReuse, @@ -227,7 +228,8 @@ HgfsSetFileType(struct inode *inode, // IN/OUT: Inode to update */ static int HgfsUnpackGetattrReply(HgfsReq *req, // IN: Reply packet - HgfsAttrInfo *attr) // IN/OUT: Attributes + HgfsAttrInfo *attr, // IN/OUT: Attributes + char **fileName) // OUT: file name { int result; char *name = NULL; @@ -267,19 +269,23 @@ HgfsUnpackGetattrReply(HgfsReq *req, // IN: Reply packet } } - if (length != 0) { + if (fileName) { + if (length != 0) { - attr->fileName = kmalloc(length + 1, GFP_KERNEL); - if (attr->fileName == NULL) { - LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackGetattrReply: out of " - "memory allocating symlink target name, ignoring\n")); - return -ENOMEM; - } + *fileName = kmalloc(length + 1, GFP_KERNEL); + if (*fileName == NULL) { + LOG(4, (KERN_DEBUG "VMware hgfs: HgfsUnpackGetattrReply: out of " + "memory allocating symlink target name, ignoring\n")); + return -ENOMEM; + } - /* Copy and convert. From now on, the symlink target is in UTF8. */ - memcpy(attr->fileName, name, length); - CPNameLite_ConvertFrom(attr->fileName, length, '/'); - attr->fileName[length] = '\0'; + /* Copy and convert. From now on, the symlink target is in UTF8. */ + memcpy(*fileName, name, length); + CPNameLite_ConvertFrom(*fileName, length, '/'); + (*fileName)[length] = '\0'; + } else { + *fileName = NULL; + } } return 0; @@ -790,8 +796,8 @@ HgfsChangeFileAttributes(struct inode *inode, // IN/OUT: Inode * for the indicated remote name, and if it succeeds copy the * results of the getattr into the provided HgfsAttrInfo. * - * attr->fileName will be allocated on success if the file is a - * symlink; it's the caller's duty to free it. + * fileName (if supplied) will be set to a newly allocated string + * if the file is a symlink; it's the caller's duty to free it. * * Results: * Returns zero on success, or a negative error on failure. @@ -804,7 +810,8 @@ HgfsChangeFileAttributes(struct inode *inode, // IN/OUT: Inode int HgfsPrivateGetattr(struct dentry *dentry, // IN: Dentry containing name - HgfsAttrInfo *attr) // OUT: Attr to copy into + HgfsAttrInfo *attr, // OUT: Attr to copy into + char **fileName) // OUT: pointer to allocated file name { struct HgfsSuperInfo *si; HgfsReq *req; @@ -850,7 +857,7 @@ HgfsPrivateGetattr(struct dentry *dentry, // IN: Dentry containing name */ switch (result) { case 0: - result = HgfsUnpackGetattrReply(req, attr); + result = HgfsUnpackGetattrReply(req, attr, fileName); break; case -EBADF: /* @@ -1076,12 +1083,10 @@ HgfsInstantiate(struct dentry *dentry, // IN: Dentry to use int error; LOG(6, (KERN_DEBUG "VMware hgfs: HgfsInstantiate: issuing getattr\n")); - newAttr.fileName = NULL; - error = HgfsPrivateGetattr(dentry, &newAttr); + error = HgfsPrivateGetattr(dentry, &newAttr, NULL); if (error) { return error; } - kfree(newAttr.fileName); attr = &newAttr; } diff --git a/open-vm-tools/modules/linux/vmhgfs/fsutil.h b/open-vm-tools/modules/linux/vmhgfs/fsutil.h index e90e87286..d1fd012b6 100644 --- a/open-vm-tools/modules/linux/vmhgfs/fsutil.h +++ b/open-vm-tools/modules/linux/vmhgfs/fsutil.h @@ -59,7 +59,6 @@ typedef struct HgfsAttrInfo { uint32 userId; /* UID */ uint32 groupId; /* GID */ uint64 hostFileId; /* Inode number */ - char *fileName; /* Either symlink target or filename */ } HgfsAttrInfo; @@ -69,7 +68,8 @@ int HgfsUnpackCommonAttr(HgfsReq *req, void HgfsChangeFileAttributes(struct inode *inode, HgfsAttrInfo const *attr); int HgfsPrivateGetattr(struct dentry *dentry, - HgfsAttrInfo *attr); + HgfsAttrInfo *attr, + char **fileName); struct inode *HgfsIget(struct super_block *sb, ino_t ino, HgfsAttrInfo const *attr); diff --git a/open-vm-tools/modules/linux/vmhgfs/inode.c b/open-vm-tools/modules/linux/vmhgfs/inode.c index 4dd79fab7..fbf529aa0 100644 --- a/open-vm-tools/modules/linux/vmhgfs/inode.c +++ b/open-vm-tools/modules/linux/vmhgfs/inode.c @@ -1098,8 +1098,7 @@ HgfsLookup(struct inode *dir, // IN: Inode of parent directory /* Do a getattr on the file to see if it exists on the server. */ inode = NULL; - attr.fileName = NULL; - error = HgfsPrivateGetattr(dentry, &attr); + error = HgfsPrivateGetattr(dentry, &attr, NULL); if (!error) { /* File exists on the server. */ @@ -1108,7 +1107,6 @@ HgfsLookup(struct inode *dir, // IN: Inode of parent directory * the server. */ inode = HgfsIget(dir->i_sb, 0, &attr); - kfree(attr.fileName); if (!inode) { error = -ENOMEM; LOG(4, (KERN_DEBUG "VMware hgfs: HgfsLookup: out of memory getting " @@ -1765,7 +1763,7 @@ HgfsAccessInt(struct dentry *dentry, // IN: dentry to check access for if (!dentry) { return 0; } - ret = HgfsPrivateGetattr(dentry, &attr); + ret = HgfsPrivateGetattr(dentry, &attr, NULL); if (ret == 0) { uint32 effectivePermissions; @@ -2094,8 +2092,7 @@ HgfsRevalidate(struct dentry *dentry) // IN: Dentry to revalidate * be current with our view of the file. */ compat_filemap_write_and_wait(dentry->d_inode->i_mapping); - attr.fileName = NULL; - error = HgfsPrivateGetattr(dentry, &attr); + error = HgfsPrivateGetattr(dentry, &attr, NULL); if (!error) { /* * If server provides file ID, we need to check whether it has changed @@ -2117,7 +2114,6 @@ HgfsRevalidate(struct dentry *dentry) // IN: Dentry to revalidate /* Update inode's attributes and reset the age. */ HgfsChangeFileAttributes(dentry->d_inode, &attr); HgfsDentryAgeReset(dentry); - kfree(attr.fileName); } } else { LOG(6, (KERN_DEBUG "VMware hgfs: HgfsRevalidate: using cached dentry " diff --git a/open-vm-tools/modules/linux/vmhgfs/link.c b/open-vm-tools/modules/linux/vmhgfs/link.c index e684fb202..9fb95a542 100644 --- a/open-vm-tools/modules/linux/vmhgfs/link.c +++ b/open-vm-tools/modules/linux/vmhgfs/link.c @@ -87,6 +87,7 @@ HgfsFollowlink(struct dentry *dentry, // IN: Dentry containing link #endif { HgfsAttrInfo attr; + char *fileName = NULL; int error; ASSERT(dentry); @@ -100,22 +101,20 @@ HgfsFollowlink(struct dentry *dentry, // IN: Dentry containing link LOG(6, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: calling " "HgfsPrivateGetattr\n")); - attr.fileName = NULL; - error = HgfsPrivateGetattr(dentry, &attr); + error = HgfsPrivateGetattr(dentry, &attr, &fileName); if (!error) { /* Let's make sure we got called on a symlink. */ - if (attr.type != HGFS_FILE_TYPE_SYMLINK || - attr.fileName == NULL) { + if (attr.type != HGFS_FILE_TYPE_SYMLINK || fileName == NULL) { LOG(6, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: got called " "on something that wasn't a symlink\n")); error = -EINVAL; } else { LOG(6, (KERN_DEBUG "VMware hgfs: HgfsFollowlink: calling " "vfs_follow_link\n")); - error = vfs_follow_link(nd, attr.fileName); + error = vfs_follow_link(nd, fileName); } - kfree(attr.fileName); + kfree(fileName); } out: @@ -151,6 +150,7 @@ HgfsReadlink(struct dentry *dentry, // IN: Dentry containing link { HgfsAttrInfo attr; + char *fileName = NULL; int error; ASSERT(dentry); @@ -163,22 +163,20 @@ HgfsReadlink(struct dentry *dentry, // IN: Dentry containing link LOG(6, (KERN_DEBUG "VMware hgfs: HgfsReadlink: calling " "HgfsPrivateGetattr\n")); - attr.fileName = NULL; - error = HgfsPrivateGetattr(dentry, &attr); + error = HgfsPrivateGetattr(dentry, &attr, &fileName); if (!error) { /* Let's make sure we got called on a symlink. */ - if (attr.type != HGFS_FILE_TYPE_SYMLINK || - attr.fileName == NULL) { + if (attr.type != HGFS_FILE_TYPE_SYMLINK || fileName == NULL) { LOG(6, (KERN_DEBUG "VMware hgfs: HgfsReadlink: got called " "on something that wasn't a symlink\n")); error = -EINVAL; } else { LOG(6, (KERN_DEBUG "VMware hgfs: HgfsReadlink: calling " "vfs_readlink\n")); - error = vfs_readlink(dentry, buffer, buflen, attr.fileName); + error = vfs_readlink(dentry, buffer, buflen, fileName); } - kfree(attr.fileName); + kfree(fileName); } return error; } diff --git a/open-vm-tools/modules/linux/vmmemctl/os.c b/open-vm-tools/modules/linux/vmmemctl/os.c index aab656777..573cfc26f 100644 --- a/open-vm-tools/modules/linux/vmmemctl/os.c +++ b/open-vm-tools/modules/linux/vmmemctl/os.c @@ -16,12 +16,10 @@ * *********************************************************/ -/* +/* * os.c -- * - * Wrappers for Linux system functions required by "vmmemctl". - * This allows customers to build their own vmmemctl driver for - * custom versioned kernels without the need for source code. + * Wrappers for Linux system functions required by "vmmemctl". */ /* @@ -37,53 +35,26 @@ #include "driver-config.h" -#include "compat_module.h" +#include #include -#include "compat_kernel.h" -#include "compat_completion.h" -#include "compat_mm.h" +#include +#include #include #include -#include -#include "compat_sched.h" -#include -#include "compat_page.h" -#include "compat_wait.h" -#include "vmmemctl_version.h" +#include #ifdef CONFIG_PROC_FS #include #include -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26) -/* - * The get_info callback of proc_dir_entry was removed in 2.6.26. - * We must therefore use the seq_file interface from that point on. - */ -#define VMW_USE_SEQ_FILE #include -#endif #endif /* CONFIG_PROC_FS */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) -#include -#include "compat_kthread.h" - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 9) -int errno; /* compat_exit() needs global errno variable. */ -#endif - -/* - * Compatibility definitions. - */ +#include "compat_sched.h" -/* - * Execute as a separate kernel thread on 2.4.x kernels. - * Allow allocations from high memory on 2.4.x kernels. - */ -#define OS_KTHREAD (1) -COMPAT_KTHREAD_DECLARE_STOP_INFO(); -#endif +#include +#include +#include "vmmemctl_version.h" #include "os.h" @@ -91,45 +62,28 @@ COMPAT_KTHREAD_DECLARE_STOP_INFO(); * Constants */ -#ifdef OS_KTHREAD /* * Use __GFP_HIGHMEM to allow pages from HIGHMEM zone. We don't - * allow wait (__GFP_WAIT) for NOSLEEP page allocations. Use - * __GFP_NOWARN, if available, to suppress page allocation failure - * warnings. + * allow wait (__GFP_WAIT) for NOSLEEP page allocations. Use + * __GFP_NOWARN, to suppress page allocation failure warnings. */ -#ifdef __GFP_NOWARN #define OS_PAGE_ALLOC_NOSLEEP (__GFP_HIGHMEM|__GFP_NOWARN) -#else -#define OS_PAGE_ALLOC_NOSLEEP (__GFP_HIGHMEM) -#endif /* * GFP_ATOMIC allocations dig deep for free pages. Maybe it is - * okay because balloon driver uses os_kmalloc_*() to only allocate - * few bytes, and the allocation requires a new page only occasionally. + * okay because balloon driver uses OS_Malloc() to only allocate + * few bytes, and the allocation requires a new page only occasionally. * Still if __GFP_NOMEMALLOC flag is available, then use it to inform - * the guest's page allocator not to use emergency pools, + * the guest's page allocator not to use emergency pools. */ -#ifdef __GFP_NOWARN - #ifdef __GFP_NOMEMALLOC #define OS_KMALLOC_NOSLEEP (GFP_ATOMIC|__GFP_NOMEMALLOC|__GFP_NOWARN) #else #define OS_KMALLOC_NOSLEEP (GFP_ATOMIC|__GFP_NOWARN) #endif -#else - -#ifdef __GFP_NOMEMALLOC -#define OS_KMALLOC_NOSLEEP (GFP_ATOMIC|__GFP_NOMEMALLOC) -#else -#define OS_KMALLOC_NOSLEEP (GFP_ATOMIC) -#endif - -#endif /* - * Use GFP_HIGHUSER when executing in a separate kernel thread + * Use GFP_HIGHUSER when executing in a separate kernel thread * context and allocation can sleep. This is less stressful to * the guest memory system, since it allows the thread to block * while memory is reclaimed, and won't take pages from emergency @@ -137,53 +91,24 @@ COMPAT_KTHREAD_DECLARE_STOP_INFO(); */ #define OS_PAGE_ALLOC_CANSLEEP (GFP_HIGHUSER) -#else /* OS_KTHREAD not defined */ - -/* 2.2.x kernel is a special case. The balloon driver is unable - * to block (sleep) because it is not executing in a separate kernel - * thread. Therefore, the driver can only use NOSLEEP page - * allocations. - * - * Use __GFP_LOW when available (2.2.x kernels) to avoid stressing - * the guest memory system, otherwise simply use GFP_ATOMIC, which - * is always defined (normally as __GFP_HIGH). - */ -#ifdef __GFP_LOW -#define OS_PAGE_ALLOC_NOSLEEP (__GFP_LOW) -#define OS_KMALLOC_NOSLEEP (GFP_ATOMIC) -#else -#define OS_PAGE_ALLOC_NOSLEEP (GFP_ATOMIC) -#define OS_KMALLOC_NOSLEEP (GFP_ATOMIC) -#endif - -#endif - /* * Types */ typedef struct { /* registered state */ - os_timer_handler handler; + OSTimerHandler *handler; void *data; int period; /* system structures */ -#ifdef OS_KTHREAD wait_queue_head_t delay; struct task_struct *task; -#else - /* termination flag */ - atomic_t stop; - - struct timer_list timer; - struct tq_struct task; -#endif } os_timer; typedef struct { /* registered state */ - os_status_handler handler; + OSStatusHandler *handler; const char *name_verbose; const char *name; } os_status; @@ -199,9 +124,7 @@ typedef struct { */ #ifdef CONFIG_PROC_FS -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) static struct proc_dir_entry *global_proc_entry; -#ifdef VMW_USE_SEQ_FILE static int os_proc_open(struct inode *, struct file *); static struct file_operations global_proc_fops = { .open = os_proc_open, @@ -209,66 +132,146 @@ static struct file_operations global_proc_fops = { .llseek = seq_lseek, .release = single_release, }; -#else -static int os_proc_read(char *, char **, off_t, int); -#endif /* VMW_USE_SEQ_FILE */ -#else -static int os_proc_read(char *, char **, off_t, int, int); -static struct proc_dir_entry global_proc_entry = { - 0, 8, "vmmemctl", S_IFREG | S_IRUGO, 1, 0, 0, 0, NULL, os_proc_read, -}; -#endif #endif /* CONFIG_PROC_FS */ static os_state global_state; + /* - * Simple Wrappers + *----------------------------------------------------------------------------- + * + * OS_Malloc -- + * + * Allocates kernel memory. + * + * Results: + * On success: Pointer to allocated memory + * On failure: NULL + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- */ -void * CDECL -os_kmalloc_nosleep(unsigned int size) +void * +OS_Malloc(size_t size) // IN { return(kmalloc(size, OS_KMALLOC_NOSLEEP)); } -void CDECL -os_kfree(void *obj, unsigned int size) + +/* + *----------------------------------------------------------------------------- + * + * OS_Free -- + * + * Free allocated kernel memory. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +OS_Free(void *ptr, // IN + size_t size) // IN { - kfree(obj); + kfree(ptr); } -void CDECL -os_bzero(void *s, unsigned int n) + +/* + *----------------------------------------------------------------------------- + * + * OS_MemZero -- + * + * Fill a memory location with 0s. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +OS_MemZero(void *ptr, // OUT + size_t size) // IN { - memset(s, 0, n); + memset(ptr, 0, size); } -void CDECL -os_memcpy(void *dest, const void *src, unsigned int size) + +/* + *----------------------------------------------------------------------------- + * + * OS_MemCopy -- + * + * Copy a memory portion into another location. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +OS_MemCopy(void *dest, // OUT + const void *src, // IN + size_t size) // IN { memcpy(dest, src, size); } -int CDECL -os_sprintf(char *str, const char *format, ...) + +/* + *----------------------------------------------------------------------------- + * + * OS_Snprintf -- + * + * Print a string into a bounded memory location. + * + * Results: + * Number of character printed including trailing \0. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +int +OS_Snprintf(char *buf, // OUT + size_t size, // IN + const char *format, // IN + ...) // IN { int result; va_list args; va_start(args, format); - result = vsprintf(str, format, args); + result = vsnprintf(buf, size, format, args); va_end(args); - return(result); + return result; } /* * System-Dependent Operations */ -char * CDECL -os_identity(void) +const char * +OS_Identity(void) { return("linux"); } @@ -282,131 +285,65 @@ os_identity(void) * booted with a mem=XX parameter) the totalram-size is equal to alloc.max. * * Returns the maximum achievable balloon size in pages - */ -unsigned int CDECL -os_predict_max_balloon_pages(void) + */ +unsigned int +OS_PredictMaxReservedPages(void) { struct sysinfo info; os_state *state = &global_state; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) - - /* - * In 2.4.0 and later, si_meminfo() is cheap. Moreover, we want to provide - * dynamic max balloon size later. So let us call si_meminfo() every - * iteration. + /* + * si_meminfo() is cheap. Moreover, we want to provide dynamic + * max balloon size later. So let us call si_meminfo() every + * iteration. */ si_meminfo(&info); - - /* In 2.4.x and later kernels, info.totalram is in pages */ - state->totalMemoryPages = info.totalram; - return(state->totalMemoryPages); - -#else - /* 2.2.x kernel */ - if (!state->totalMemoryPages) { - si_meminfo(&info); /* In 2.2.x, si_meminfo() is a costly operation */ - /* In 2.2.x kernels, info.totalram is in bytes */ - state->totalMemoryPages = info.totalram >> PAGE_SHIFT; - } - return(state->totalMemoryPages); - -#endif + /* info.totalram is in pages */ + state->totalMemoryPages = info.totalram; + return state->totalMemoryPages; } /* * Use newer alloc_page() interface on 2.4.x kernels. * Use "struct page *" value as page handle for clients. */ -unsigned long CDECL -os_addr_to_ppn(unsigned long addr) +unsigned long +OS_AddrToPPN(unsigned long addr) { struct page *page = (struct page *) addr; - return(page_to_pfn(page)); + + return page_to_pfn(page); } -unsigned long CDECL -os_alloc_reserved_page(int can_sleep) +unsigned long +OS_AllocReservedPage(int canSleep) { - struct page *page; - /* allocate page */ - if (can_sleep) { -#ifdef OS_KTHREAD - page = alloc_page(OS_PAGE_ALLOC_CANSLEEP); -#else - return 0; -#endif - } else { - page = alloc_page(OS_PAGE_ALLOC_NOSLEEP); - } - return((unsigned long) page); + struct page *page = alloc_page(canSleep ? + OS_PAGE_ALLOC_CANSLEEP : OS_PAGE_ALLOC_NOSLEEP); + + return (unsigned long)page; } -void CDECL -os_free_reserved_page(unsigned long addr) +void +OS_FreeReservedPage(unsigned long addr) { /* deallocate page */ struct page *page = (struct page *) addr; __free_page(page); } -#ifndef OS_KTHREAD -static void os_timer_add(os_timer *t) -{ - /* schedule timer callback */ - struct timer_list *timer = &t->timer; - timer->expires = jiffies + t->period; - add_timer(timer); -} - -static void os_timer_remove(os_timer *t) -{ - /* deschedule timer callback */ - struct timer_list *timer = &t->timer; - (void) del_timer(timer); -} - -static void os_timer_bh(void *data) -{ - os_timer *t = (os_timer *) data; - - if (!atomic_read(&t->stop)) { - /* execute registered handler, rearm timer */ - (*(t->handler))(t->data); - os_timer_add(t); - } -} - -static void os_timer_internal(ulong data) -{ - os_timer *t = (os_timer *) data; - - /* perform real work in registered bottom-half handler */ - queue_task(&t->task, &tq_immediate); - mark_bh(IMMEDIATE_BH); -} -#endif - -void CDECL -os_timer_init(os_timer_handler handler, void *data, int period) +void +OS_TimerInit(OSTimerHandler *handler, // IN + void *clientData, // IN + int period) // IN { os_timer *t = &global_state.timer; t->handler = handler; - t->data = data; + t->data = clientData; t->period = period; -#ifndef OS_KTHREAD - atomic_set(&t->stop, 0); - t->task.routine = os_timer_bh; - t->task.data = t; - /* initialize timer state */ - init_timer(&t->timer); - t->timer.function = os_timer_internal; - t->timer.data = (ulong) t; -#endif } -#ifdef OS_KTHREAD static int os_timer_thread_loop(void *data) { os_timer *t = (os_timer *) data; @@ -419,98 +356,77 @@ static int os_timer_thread_loop(void *data) /* sleep for specified period */ wait_event_interruptible_timeout(t->delay, compat_wait_check_freezing() || - compat_kthread_should_stop(), + kthread_should_stop(), t->period); compat_try_to_freeze(); - if (compat_kthread_should_stop()) { + if (kthread_should_stop()) { break; } /* execute registered handler */ - (*(t->handler))(t->data); + t->handler(t->data); } /* terminate */ return(0); } -static int os_timer_thread_start(os_timer *t) +void +OS_TimerStart(void) { + os_timer *t = &global_state.timer; os_status *s = &global_state.status; /* initialize sync objects */ init_waitqueue_head(&t->delay); /* create kernel thread */ - t->task = compat_kthread_run(os_timer_thread_loop, t, "vmmemctl"); + t->task = kthread_run(os_timer_thread_loop, t, "vmmemctl"); if (IS_ERR(t->task)) { /* fail */ printk(KERN_WARNING "%s: unable to create kernel thread\n", s->name); - return(-1); - } - - if (OS_DEBUG) { + } else if (OS_DEBUG) { printk(KERN_DEBUG "%s: started kernel thread pid=%d\n", s->name, t->task->pid); } - - return(0); } -static void os_timer_thread_stop(os_timer *t) +void +OS_TimerStop(void) { - compat_kthread_stop(t->task); + kthread_stop(global_state.timer.task); } -#endif -void CDECL -os_timer_start(void) +unsigned int +OS_TimerHz(void) { - os_timer *t = &global_state.timer; - -#ifdef OS_KTHREAD - os_timer_thread_start(t); -#else - /* clear termination flag */ - atomic_set(&t->stop, 0); - - os_timer_add(t); -#endif + return HZ; } -void CDECL -os_timer_stop(void) -{ - os_timer *t = &global_state.timer; -#ifdef OS_KTHREAD - os_timer_thread_stop(t); -#else - /* set termination flag */ - atomic_set(&t->stop, 1); - - os_timer_remove(t); -#endif -} - -unsigned int CDECL -os_timer_hz(void) -{ - return HZ; -} +/* + *----------------------------------------------------------------------------- + * + * OS_Yield -- + * + * Yield the CPU, if needed. + * + * Results: + * None + * + * Side effects: + * This thread might get descheduled, other threads might get scheduled. + * + *----------------------------------------------------------------------------- + */ -void CDECL -os_yield(void) +void +OS_Yield(void) { -#ifdef OS_KTHREAD cond_resched(); -#else - /* Do nothing. Timer callbacks should not sleep. */ -#endif } #ifdef CONFIG_PROC_FS -#ifdef VMW_USE_SEQ_FILE static int os_proc_show(struct seq_file *f, void *data) { @@ -529,8 +445,8 @@ static int os_proc_show(struct seq_file *f, goto out; } - s->handler(buf); - + s->handler(buf, PAGE_SIZE); + if (seq_puts(f, buf) != 0) { err = -ENOSPC; goto out; @@ -550,37 +466,12 @@ static int os_proc_open(struct inode *inode, return single_open(file, os_proc_show, NULL); } -#else -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) -static int os_proc_read(char *buf, - char **start, - off_t offset, - int length) -#else -static int os_proc_read(char *buf, - char **start, - off_t offset, - int length, - int unused) #endif -{ - os_status *s = &global_state.status; - /* done if no handler */ - if (s->handler == NULL) { - return(0); - } - - /* invoke registered handler */ - return(s->handler(buf)); -} -#endif /* VMW_USE_SEQ_FILE */ -#endif - -void CDECL -os_init(const char *name, +void +OS_Init(const char *name, const char *name_verbose, - os_status_handler handler) + OSStatusHandler *handler) { os_state *state = &global_state; static int initialized = 0; @@ -592,11 +483,7 @@ os_init(const char *name, /* prevent module unload with extra reference */ if (OS_DISABLE_UNLOAD) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 48) - MOD_INC_USE_COUNT; -#else try_module_get(THIS_MODULE); -#endif } /* zero global state */ @@ -609,40 +496,24 @@ os_init(const char *name, #ifdef CONFIG_PROC_FS /* register procfs device */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) global_proc_entry = create_proc_entry("vmmemctl", S_IFREG | S_IRUGO, NULL); if (global_proc_entry != NULL) { -#ifdef VMW_USE_SEQ_FILE global_proc_entry->proc_fops = &global_proc_fops; -#else - global_proc_entry->get_info = os_proc_read; -#endif /* VMW_USE_SEQ_FILE */ } -#else - proc_register(&proc_root, &global_proc_entry); -#endif #endif /* CONFIG_PROC_FS */ /* log device load */ printk(KERN_INFO "%s initialized\n", state->status.name_verbose); } -void CDECL -os_cleanup(void) +void +OS_Cleanup(void) { os_status *s = &global_state.status; - int err; #ifdef CONFIG_PROC_FS /* unregister procfs entry */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) remove_proc_entry("vmmemctl", NULL); - err = 0; -#else - if ((err = proc_unregister(&proc_root, global_proc_entry.low_ino)) != 0) { - printk(KERN_WARNING "%s: unable to unregister procfs entry (%d)\n", s->name, err); - } -#endif #endif /* CONFIG_PROC_FS */ /* log device unload */ diff --git a/open-vm-tools/modules/linux/vmmemctl/os.h b/open-vm-tools/modules/linux/vmmemctl/os.h index 8a5f690e6..b991edd71 100644 --- a/open-vm-tools/modules/linux/vmmemctl/os.h +++ b/open-vm-tools/modules/linux/vmmemctl/os.h @@ -16,62 +16,49 @@ * *********************************************************/ -/* +/* * os.h -- * - * Definitions for OS-specific wrapper functions required - * by "vmmemctl". This allows customers to build their own - * vmmemctl driver for custom versioned kernels without the - * need for source code. + * Definitions for OS-specific wrapper functions required by "vmmemctl". */ #ifndef OS_H #define OS_H -/* - * Needs fixing for 64bit OSes - */ -#ifndef __x86_64__ -#define CDECL __attribute__((cdecl, regparm(0))) -#else -#define CDECL -#endif - /* * Types */ -typedef void CDECL (*os_timer_handler)(void *); -typedef int CDECL (*os_status_handler)(char *); +typedef void OSTimerHandler(void *clientData); +typedef int OSStatusHandler(char *buf, size_t size); /* * Operations */ -extern void CDECL *os_kmalloc_nosleep(unsigned int size); -extern void CDECL os_kfree(void *obj, unsigned int size); -extern void CDECL os_yield(void); -extern void CDECL os_bzero(void *s, unsigned int n); -extern void CDECL os_memcpy(void *dest, const void *src, unsigned int size); -extern int CDECL os_sprintf(char *str, const char *format, ...); - -extern unsigned long CDECL os_addr_to_ppn(unsigned long addr); -extern unsigned long CDECL os_alloc_reserved_page(int can_sleep); -extern void CDECL os_free_reserved_page(unsigned long page); +extern void OS_Init(const char *name, + const char *nameVerbose, + OSStatusHandler *handler); +extern void OS_Cleanup(void); +extern const char *OS_Identity(void); -extern void CDECL os_timer_init(os_timer_handler handler, void *data, int period); -extern void CDECL os_timer_start(void); -extern void CDECL os_timer_stop(void); +extern void OS_MemZero(void *ptr, size_t size); +extern void OS_MemCopy(void *dest, const void *src, size_t size); +extern int OS_Snprintf(char *buf, size_t size, const char *format, ...); -extern void CDECL os_init(const char *name, - const char *name_verbose, - os_status_handler handler); -extern void CDECL os_cleanup(void); +extern void *OS_Malloc(size_t size); +extern void OS_Free(void *ptr, size_t size); -extern char CDECL *os_identity(void); +extern void OS_Yield(void); -extern unsigned int CDECL os_predict_max_balloon_pages(void); +extern unsigned int OS_TimerHz(void); +extern void OS_TimerInit(OSTimerHandler *handler, void *clientData, int period); +extern void OS_TimerStart(void); +extern void OS_TimerStop(void); -extern unsigned int CDECL os_timer_hz(void); +extern unsigned int OS_PredictMaxReservedPages(void); +extern unsigned long OS_AddrToPPN(unsigned long addr); +extern unsigned long OS_AllocReservedPage(int canSleep); +extern void OS_FreeReservedPage(unsigned long page); #endif /* OS_H */ diff --git a/open-vm-tools/modules/linux/vmmemctl/vmballoon.c b/open-vm-tools/modules/linux/vmmemctl/vmballoon.c index a88eea718..91212ec8f 100644 --- a/open-vm-tools/modules/linux/vmmemctl/vmballoon.c +++ b/open-vm-tools/modules/linux/vmmemctl/vmballoon.c @@ -16,18 +16,18 @@ * *********************************************************/ -/* +/* * vmballoon.c -- * - * VMware server physical memory management driver for Unix-ish - * (Linux, FreeBSD, Solaris) guests. The driver acts like a - * "balloon" that can be inflated to reclaim physical pages by - * reserving them in the guest and invalidating them in the - * monitor, freeing up the underlying machine pages so they can - * be allocated to other guests. The balloon can also be - * deflated to allow the guest to use more physical memory. - * Higher level policies can control the sizes of balloons in VMs - * in order to manage physical memory resources. + * VMware physical memory management driver for Unix-ish + * (Linux, FreeBSD, Solaris, Mac OS) guests. The driver acts like + * a "balloon" that can be inflated to reclaim physical pages by + * reserving them in the guest and invalidating them in the + * monitor, freeing up the underlying machine pages so they can + * be allocated to other guests. The balloon can also be + * deflated to allow the guest to use more physical memory. + * Higher level policies can control the sizes of balloons in VMs + * in order to manage physical memory resources. */ #ifdef __cplusplus @@ -38,12 +38,12 @@ extern "C" { * Compile-Time Options */ -#define BALLOON_RATE_ADAPT (1) +#define BALLOON_RATE_ADAPT (1) -#define BALLOON_DEBUG (1) -#define BALLOON_DEBUG_VERBOSE (0) +#define BALLOON_DEBUG (1) +#define BALLOON_DEBUG_VERBOSE (0) -#define BALLOON_STATS +#define BALLOON_STATS #define BALLOON_STATS_PROCFS /* @@ -65,38 +65,38 @@ extern "C" { #define NULL 0 #endif -#define BALLOON_NAME "vmmemctl" -#define BALLOON_NAME_VERBOSE "VMware memory control driver" +#define BALLOON_NAME "vmmemctl" +#define BALLOON_NAME_VERBOSE "VMware memory control driver" -#define BALLOON_PROTOCOL_VERSION (2) +#define BALLOON_PROTOCOL_VERSION (2) -#define BALLOON_CHUNK_PAGES (1000) +#define BALLOON_CHUNK_PAGES (1000) -#define BALLOON_NOSLEEP_ALLOC_MAX (16384) +#define BALLOON_NOSLEEP_ALLOC_MAX (16384) -#define BALLOON_RATE_ALLOC_MIN (512) -#define BALLOON_RATE_ALLOC_MAX (2048) -#define BALLOON_RATE_ALLOC_INC (16) +#define BALLOON_RATE_ALLOC_MIN (512) +#define BALLOON_RATE_ALLOC_MAX (2048) +#define BALLOON_RATE_ALLOC_INC (16) -#define BALLOON_RATE_FREE_MIN (512) -#define BALLOON_RATE_FREE_MAX (16384) -#define BALLOON_RATE_FREE_INC (16) +#define BALLOON_RATE_FREE_MIN (512) +#define BALLOON_RATE_FREE_MAX (16384) +#define BALLOON_RATE_FREE_INC (16) -#define BALLOON_ERROR_PAGES (16) +#define BALLOON_ERROR_PAGES (16) -/* +/* * When guest is under memory pressure, use a reduced page allocation * rate for next several cycles. */ -#define SLOW_PAGE_ALLOCATION_CYCLES (4) +#define SLOW_PAGE_ALLOCATION_CYCLES (4) -/* +/* * Move it to bora/public/balloon_def.h later, if needed. Note that * BALLOON_PAGE_ALLOC_FAILURE is an internal error code used for * distinguishing page allocation failures from monitor-backdoor errors. * We use value 1000 because all monitor-backdoor error codes are < 1000. */ -#define BALLOON_PAGE_ALLOC_FAILURE (1000) +#define BALLOON_PAGE_ALLOC_FAILURE (1000) // Maximum number of page allocations without yielding processor #define BALLOON_ALLOC_YIELD_THRESHOLD (1024) @@ -156,7 +156,7 @@ static Balloon globalBalloon; static int BalloonGuestType(void); static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep); -static void BalloonPrimFreePage(unsigned long page); +static void BalloonPrimFreePage(unsigned long page); static int Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType); static int Balloon_FreePage(Balloon *b, int monitorUnlock); @@ -165,7 +165,7 @@ static void Balloon_Reset(Balloon *b); static void Balloon_StartTimer(Balloon *b); static void Balloon_StopTimer(Balloon *b); -static void CDECL Balloon_BH(void *data); +static void BalloonTimerHandler(void *clientData); static int Balloon_MonitorStart(Balloon *b); static int Balloon_MonitorGuestType(Balloon *b); @@ -177,51 +177,43 @@ static int Balloon_MonitorUnlockPage(Balloon *b, unsigned long addr); * Macros */ -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif - -#ifdef BALLOON_STATS -#define STATS_INC(stat) (stat)++ +#ifdef BALLOON_STATS +#define STATS_INC(stat) (stat)++ #else -#define STATS_INC(stat) +#define STATS_INC(stat) #endif /* * Macros to generate operations for simple lists of OBJ. * OBJ must contain next and prev fields. - * */ -#define GENERATE_LIST_INSERT(OBJ) \ -static void OBJ ## _Insert(OBJ **head, OBJ *obj) \ -{ \ - OBJ *h = *head; \ - \ - /* add element to head of list */ \ - obj->next = h; \ - if (h != NULL) { \ - h->prev = obj; \ - } \ - *head = obj; \ - obj->prev = NULL; \ +#define GENERATE_LIST_INSERT(OBJ) \ +static void OBJ ## _Insert(OBJ **head, OBJ *obj) \ +{ \ + OBJ *h = *head; \ + \ + /* add element to head of list */ \ + obj->next = h; \ + if (h != NULL) { \ + h->prev = obj; \ + } \ + *head = obj; \ + obj->prev = NULL; \ } -#define GENERATE_LIST_REMOVE(OBJ) \ -static void OBJ ## _Remove(OBJ **head, OBJ *obj) \ -{ \ - /* splice element out of list */ \ - if (obj->prev != NULL) { \ - obj->prev->next = obj->next; \ - } else { \ - *head = obj->next; \ - } \ - if (obj->next != NULL) { \ - obj->next->prev = obj->prev; \ - } \ +#define GENERATE_LIST_REMOVE(OBJ) \ +static void OBJ ## _Remove(OBJ **head, OBJ *obj) \ +{ \ + /* splice element out of list */ \ + if (obj->prev != NULL) { \ + obj->prev->next = obj->next; \ + } else { \ + *head = obj->next; \ + } \ + if (obj->next != NULL) { \ + obj->next->prev = obj->prev; \ + } \ } /* @@ -235,25 +227,28 @@ GENERATE_LIST_REMOVE(BalloonChunk); * Procfs Operations */ + /* *---------------------------------------------------------------------- * * BalloonProcRead -- * * Ballon driver status reporting routine. Note that this is only - * used for Linux. + * used for Linux. * * Results: * Writes ASCII status information into "buf". - * Returns number of bytes written. + * Returns number of bytes written. * * Side effects: * None. * *---------------------------------------------------------------------- */ -static int CDECL -BalloonProcRead(char *buf) + +static int +BalloonProcRead(char *buf, // OUT + size_t size) // IN { int len = 0; BalloonStats stats; @@ -261,14 +256,14 @@ BalloonProcRead(char *buf) BalloonGetStats(&stats); /* format size info */ - len += os_sprintf(buf + len, + len += OS_Snprintf(buf + len, size - len, "target: %8d pages\n" "current: %8d pages\n", stats.nPagesTarget, stats.nPages); /* format rate info */ - len += os_sprintf(buf + len, + len += OS_Snprintf(buf + len, size - len, "rateNoSleepAlloc: %8d pages/sec\n" "rateSleepAlloc: %8d pages/sec\n" "rateFree: %8d pages/sec\n", @@ -276,8 +271,8 @@ BalloonProcRead(char *buf) stats.rateAlloc, stats.rateFree); -#ifdef BALLOON_STATS_PROCFS - len += os_sprintf(buf + len, +#ifdef BALLOON_STATS_PROCFS + len += OS_Snprintf(buf + len, size - len, "\n" "timer: %8u\n" "start: %8u (%4u failed)\n" @@ -305,7 +300,7 @@ BalloonProcRead(char *buf) stats.primErrorPageFree); #endif - return(len); + return len; } /* @@ -318,7 +313,7 @@ BalloonProcRead(char *buf) * AddrToPPN -- * * Return the physical page number corresponding to the specified - * Linux kernel-mapped address. + * kernel-mapped address. * * Results: * Returns PPN for "addr". @@ -331,7 +326,7 @@ BalloonProcRead(char *buf) static inline unsigned long AddrToPPN(unsigned long addr) { - return(os_addr_to_ppn(addr)); + return OS_AddrToPPN(addr); } /* @@ -341,12 +336,12 @@ AddrToPPN(unsigned long addr) * * Attempts to allocate and reserve a physical page. * - * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP: - * The allocation can wait (sleep) for page writeout (swap) - * by the guest. - * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP: - * If allocation of a page requires disk writeout, then - * just fail. DON'T sleep. + * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP: + * The allocation can wait (sleep) for page writeout (swap) + * by the guest. + * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP: + * If allocation of a page requires disk writeout, then + * just fail. DON'T sleep. * * Results: * Returns the physical address of the allocated page, or 0 if error. @@ -359,7 +354,7 @@ AddrToPPN(unsigned long addr) static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep) { - return(os_alloc_reserved_page(canSleep)); + return OS_AllocReservedPage(canSleep); } /* @@ -380,7 +375,7 @@ BalloonPrimAllocPage(BalloonPageAllocType canSleep) static void BalloonPrimFreePage(unsigned long page) { - return(os_free_reserved_page(page)); + return OS_FreeReservedPage(page); } /* @@ -389,7 +384,7 @@ BalloonPrimFreePage(unsigned long page) * BalloonGuestType -- * * Return balloon guest OS identifier obtained by parsing - * system-dependent identity string. + * system-dependent identity string. * * Results: * Returns one of BALLOON_GUEST_{LINUX,BSD,SOLARIS,UNKNOWN}. @@ -402,11 +397,11 @@ BalloonPrimFreePage(unsigned long page) static int BalloonGuestType(void) { - char *identity; + const char *identity; /* obtain OS identify string */ - identity = os_identity(); - + identity = OS_Identity(); + /* unknown if not specified */ if (identity == NULL) { return(BALLOON_GUEST_UNKNOWN); @@ -416,19 +411,19 @@ BalloonGuestType(void) switch (identity[0]) { case 'l': case 'L': - return(BALLOON_GUEST_LINUX); + return BALLOON_GUEST_LINUX; case 'b': case 'B': - return(BALLOON_GUEST_BSD); + return BALLOON_GUEST_BSD; case 's': case 'S': - return(BALLOON_GUEST_SOLARIS); + return BALLOON_GUEST_SOLARIS; default: break; } /* unknown */ - return(BALLOON_GUEST_UNKNOWN); + return BALLOON_GUEST_UNKNOWN; } /* @@ -443,7 +438,7 @@ void BalloonGetStats(BalloonStats *stats) /* * Copy statistics out of global structure. */ - os_memcpy(stats, &b->stats, sizeof (BalloonStats)); + OS_MemCopy(stats, &b->stats, sizeof (BalloonStats)); /* * Fill in additional information about size and rates, which is @@ -465,37 +460,41 @@ void BalloonGetStats(BalloonStats *stats) * BalloonChunk_Create -- * * Creates a new BalloonChunk object capable of tracking - * BALLOON_CHUNK_PAGES PPNs. + * BALLOON_CHUNK_PAGES PPNs. * - * We do not bother to define two versions (NOSLEEP and CANSLEEP) - * of os_kmalloc because Chunk_Create does not require a new page - * often. + * We do not bother to define two versions (NOSLEEP and CANSLEEP) + * of OS_Malloc because Chunk_Create does not require a new page + * often. * * Results: - * Returns initialized BalloonChunk, or NULL if error. + * On success: initialized BalloonChunk + * On failure: NULL * * Side effects: - * None. + * None * *---------------------------------------------------------------------- */ + static BalloonChunk * BalloonChunk_Create(void) { BalloonChunk *chunk; /* allocate memory, fail if unable */ - if ((chunk = (BalloonChunk *) os_kmalloc_nosleep(sizeof(BalloonChunk))) == NULL) { - return(NULL); + chunk = OS_Malloc(sizeof *chunk); + if (chunk == NULL) { + return NULL; } /* initialize */ - os_bzero(chunk, sizeof(BalloonChunk)); + OS_MemZero(chunk, sizeof *chunk); /* everything OK */ - return(chunk); + return chunk; } + /* *---------------------------------------------------------------------- * @@ -515,7 +514,7 @@ static void BalloonChunk_Destroy(BalloonChunk *chunk) { /* reclaim storage */ - os_kfree(chunk, sizeof (BalloonChunk)); + OS_Free(chunk, sizeof *chunk); } /* @@ -542,7 +541,7 @@ static int Balloon_Init(Balloon *b) { /* clear state */ - os_bzero(b, sizeof(Balloon)); + OS_MemZero(b, sizeof *b); /* initialize rates */ b->rateAlloc = BALLOON_RATE_ALLOC_MAX; @@ -580,7 +579,7 @@ Balloon_Deallocate(Balloon *b) (void) Balloon_FreePage(b, FALSE); if (++cnt >= b->rateFree) { cnt = 0; - os_yield(); + OS_Yield(); } } } @@ -591,7 +590,7 @@ Balloon_Deallocate(Balloon *b) * Balloon_Reset -- * * Resets balloon "b" to empty state. Frees all allocated pages - * and attempts to reset contact with the monitor. + * and attempts to reset contact with the monitor. * * Results: * None. @@ -623,12 +622,12 @@ Balloon_Reset(Balloon *b) /* *---------------------------------------------------------------------- * - * Balloon_BH -- + * BalloonTimerHandler -- * * Balloon bottom half handler. Contacts monitor via backdoor - * to obtain balloon size target, and starts adjusting balloon - * size to achieve target by allocating or deallocating pages. - * Resets balloon if requested by the monitor. + * to obtain balloon size target, and starts adjusting balloon + * size to achieve target by allocating or deallocating pages. + * Resets balloon if requested by the monitor. * * Results: * None. @@ -638,10 +637,10 @@ Balloon_Reset(Balloon *b) * *---------------------------------------------------------------------- */ -static void CDECL -Balloon_BH(void *data) +static void +BalloonTimerHandler(void *clientData) { - Balloon *b = (Balloon *) data; + Balloon *b = (Balloon *) clientData; uint32 target; int status; @@ -679,14 +678,14 @@ Balloon_BH(void *data) * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ static void Balloon_StartTimer(Balloon *b) { - os_timer_start(); + OS_TimerStart(); } /* @@ -700,14 +699,14 @@ Balloon_StartTimer(Balloon *b) * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ static void Balloon_StopTimer(Balloon *b) { - os_timer_stop(); + OS_TimerStop(); } @@ -717,14 +716,14 @@ Balloon_StopTimer(Balloon *b) * Balloon_ErrorPagesAlloc -- * * Attempt to add "page" to list of non-balloonable pages - * associated with "b". + * associated with "b". * * Results: - * Returns BALLOON_SUCCESS iff successful, or BALLOON_FAILURE - * if non-balloonable page list is already full. + * On success: BALLOON_SUCCESS + * On failure: BALLOON_FAILURE (non-balloonable page list is already full) * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -749,13 +748,13 @@ Balloon_ErrorPagesAlloc(Balloon *b, unsigned long page) * Balloon_ErrorPagesFree -- * * Deallocates all pages on the list of non-balloonable pages - * associated with "b". + * associated with "b". * * Results: - * None. + * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -766,7 +765,7 @@ Balloon_ErrorPagesFree(Balloon *b) /* free all non-balloonable "error" pages */ for (i = 0; i < b->errors.nextPage; i++) { - BalloonPrimFreePage(b->errors.page[i]); + BalloonPrimFreePage(b->errors.page[i]); b->errors.page[i] = 0; STATS_INC(b->stats.primErrorPageFree); } @@ -779,13 +778,13 @@ Balloon_ErrorPagesFree(Balloon *b) * Balloon_AllocPage -- * * Attempts to allocate a physical page, inflating balloon "b". - * Informs monitor of PPN for allocated page via backdoor. + * Informs monitor of PPN for allocated page via backdoor. * * Results: * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -854,14 +853,14 @@ Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType) * Balloon_FreePage -- * * Attempts to deallocate a physical page, deflating balloon "b". - * Informs monitor of PPN for deallocated page via backdoor if - * "monitorUnlock" is specified. + * Informs monitor of PPN for deallocated page via backdoor if + * "monitorUnlock" is specified. * * Results: * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -929,15 +928,15 @@ Balloon_FreePage(Balloon *b, int monitorUnlock) * * BalloonDecreaseRateAlloc -- * - * Wrapper to quickly reduce the page allocation rate. This function - * is called only when a CANSLEEP allocation fails. This implies severe - * memory pressure inside the guest, so quickly decrease the rateAlloc. + * Wrapper to quickly reduce the page allocation rate. This function + * is called only when a CANSLEEP allocation fails. This implies severe + * memory pressure inside the guest, so quickly decrease the rateAlloc. * * Results: * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -954,27 +953,27 @@ BalloonDecreaseRateAlloc(Balloon *b) * * BalloonIncreaseRateAlloc -- * - * Wrapper to increase the page allocation rate. + * Wrapper to increase the page allocation rate. * - * This function is called when the balloon target is met or - * b->rateAlloc (or more) pages have been successfully allocated. - * This implies that the guest may not be under high memory - * pressure. So let us increase the rateAlloc. + * This function is called when the balloon target is met or + * b->rateAlloc (or more) pages have been successfully allocated. + * This implies that the guest may not be under high memory + * pressure. So let us increase the rateAlloc. * - * If meeting balloon target requires less than b->rateAlloc - * pages, then we do not change the page allocation rate. + * If meeting balloon target requires less than b->rateAlloc + * pages, then we do not change the page allocation rate. * - * If the number of pages successfully allocated (nAlloc) is far - * higher than b->rateAlloc, then it implies that NOSLEEP - * allocations are highly successful. Therefore, we predict that - * the guest is under no memory pressure, and so increase - * b->rateAlloc quickly. + * If the number of pages successfully allocated (nAlloc) is far + * higher than b->rateAlloc, then it implies that NOSLEEP + * allocations are highly successful. Therefore, we predict that + * the guest is under no memory pressure, and so increase + * b->rateAlloc quickly. * * Results: * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -983,7 +982,7 @@ BalloonIncreaseRateAlloc(Balloon *b, uint32 nAlloc) { if (BALLOON_RATE_ADAPT) { if (nAlloc >= b->rateAlloc) { - uint32 mult = nAlloc / b->rateAlloc; + uint32 mult = nAlloc / b->rateAlloc; b->rateAlloc = MIN(b->rateAlloc + mult * BALLOON_RATE_ALLOC_INC, BALLOON_RATE_ALLOC_MAX); } @@ -1001,7 +1000,7 @@ BalloonIncreaseRateAlloc(Balloon *b, uint32 nAlloc) * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1011,7 +1010,7 @@ BalloonInflate(Balloon *b, uint32 target) int status, allocations = 0; uint32 i, nAllocNoSleep, nAllocCanSleep; - /* + /* * First try NOSLEEP page allocations to inflate balloon. * * If we do not throttle nosleep allocations, we can drain all @@ -1019,10 +1018,10 @@ BalloonInflate(Balloon *b, uint32 target) * As a side-effect, draining free pages helps to inform (force) * the guest to start swapping if balloon target is not met yet, * which is a desired behavior. However, balloon driver can consume - * all available CPU cycles if too many pages are allocated in a - * second. Therefore, we throttle nosleep allocations even when - * the guest is not under memory pressure. OTOH, if we have already - * predicted that the guest is under memory pressure, then we + * all available CPU cycles if too many pages are allocated in a + * second. Therefore, we throttle nosleep allocations even when + * the guest is not under memory pressure. OTOH, if we have already + * predicted that the guest is under memory pressure, then we * slowdown page allocations considerably. */ if (b->slowPageAllocationCycles > 0) { @@ -1036,16 +1035,16 @@ BalloonInflate(Balloon *b, uint32 target) status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_NOSLEEP); if (status != BALLOON_SUCCESS) { if (status != BALLOON_PAGE_ALLOC_FAILURE) { - /* + /* * Not a page allocation failure, so release non-balloonable * pages, and fail. */ Balloon_ErrorPagesFree(b); return(status); } - /* - * NOSLEEP page allocation failed, so the guest is under memory - * pressure. Let us slowdown page allocations for next few + /* + * NOSLEEP page allocation failed, so the guest is under memory + * pressure. Let us slowdown page allocations for next few * cycles so that the guest gets out of memory pressure. */ b->slowPageAllocationCycles = SLOW_PAGE_ALLOCATION_CYCLES; @@ -1053,12 +1052,12 @@ BalloonInflate(Balloon *b, uint32 target) } if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) { - os_yield(); + OS_Yield(); allocations = 0; } } - /* + /* * Check whether nosleep allocation successfully zapped nAllocNoSleep * pages. */ @@ -1068,7 +1067,7 @@ BalloonInflate(Balloon *b, uint32 target) Balloon_ErrorPagesFree(b); return(BALLOON_SUCCESS); } else { - /* + /* * NOSLEEP allocation failed, so the guest is under memory pressure. * If already b->rateAlloc pages were zapped, then succeed. Otherwise, * try CANSLEEP allocation. @@ -1084,14 +1083,14 @@ BalloonInflate(Balloon *b, uint32 target) } } - /* + /* * Use CANSLEEP page allocation to inflate balloon if below target. * * Sleep allocations are required only when nosleep allocation fails. * This implies that the guest is already under memory pressure, so * let us always throttle canSleep allocations. The total number pages - * allocated using noSleep and canSleep methods is throttled at - * b->rateAlloc per second when the guest is under memory pressure. + * allocated using noSleep and canSleep methods is throttled at + * b->rateAlloc per second when the guest is under memory pressure. */ nAllocCanSleep = target - b->nPages; nAllocCanSleep = MIN(nAllocCanSleep, b->rateAlloc - nAllocNoSleep); @@ -1101,7 +1100,7 @@ BalloonInflate(Balloon *b, uint32 target) status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_CANSLEEP); if(status != BALLOON_SUCCESS) { if (status == BALLOON_PAGE_ALLOC_FAILURE) { - /* + /* * CANSLEEP page allocation failed, so guest is under severe * memory pressure. Quickly decrease rateAlloc. */ @@ -1113,17 +1112,17 @@ BalloonInflate(Balloon *b, uint32 target) } if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) { - os_yield(); + OS_Yield(); allocations = 0; } } - /* + /* * Either met the balloon target or b->rateAlloc pages have been * successfully zapped. */ BalloonIncreaseRateAlloc(b, nAllocNoSleep + nAllocCanSleep); - + /* release non-balloonable pages, succeed */ Balloon_ErrorPagesFree(b); return(BALLOON_SUCCESS); @@ -1140,7 +1139,7 @@ BalloonInflate(Balloon *b, uint32 target) * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1149,7 +1148,7 @@ BalloonDeflate(Balloon *b, uint32 target) { int status, i; uint32 nFree = b->nPages - target; - + /* limit deallocation rate */ nFree = MIN(nFree, b->rateFree); @@ -1173,20 +1172,20 @@ BalloonDeflate(Balloon *b, uint32 target) /* everything OK */ return(BALLOON_SUCCESS); } - + /* *---------------------------------------------------------------------- * * Balloon_AdjustSize -- * * Attempts to allocate or deallocate physical pages in order - * to reach desired "target" size for balloon "b". + * to reach desired "target" size for balloon "b". * * Results: * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1224,10 +1223,10 @@ Balloon_AdjustSize(Balloon *b, uint32 target) * Attempts to contact monitor via backdoor to begin operation. * * Results: - * Returns BALLOON_SUCCESS if successful, otherwise error code. + * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1266,10 +1265,10 @@ Balloon_MonitorStart(Balloon *b) * Attempts to contact monitor and report guest OS identity. * * Results: - * Returns BALLOON_SUCCESS if successful, otherwise error code. + * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1311,24 +1310,24 @@ Balloon_MonitorGuestType(Balloon *b) * Balloon_MonitorGetTarget -- * * Attempts to contact monitor via backdoor to obtain desired - * balloon size. + * balloon size. * - * Predicts the maximum achievable balloon size and sends it - * to vmm => vmkernel via vEbx register. + * Predicts the maximum achievable balloon size and sends it + * to vmm => vmkernel via vEbx register. * - * os_predict_max_balloon_pages() returns either predicted max balloon - * pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario, - * vmkernel uses global config options for determining a guest's max - * balloon size. Note that older vmballoon drivers set vEbx to - * BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel - * will fallback to config-based max balloon size estimation. + * OS_PredictMaxReservedPages() returns either predicted max balloon + * pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario, + * vmkernel uses global config options for determining a guest's max + * balloon size. Note that older vmballoon drivers set vEbx to + * BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel + * will fallback to config-based max balloon size estimation. * * Results: - * If successful, sets "target" to value obtained from monitor, + * If successful, sets "target" to value obtained from monitor, * and returns BALLOON_SUCCESS. Otherwise returns error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1340,7 +1339,7 @@ Balloon_MonitorGetTarget(Balloon *b, uint32 *target) /* prepare backdoor args */ bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_TARGET; - bp.in.size = os_predict_max_balloon_pages(); + bp.in.size = OS_PredictMaxReservedPages(); /* invoke backdoor */ Backdoor_Balloon(&bp); @@ -1369,14 +1368,14 @@ Balloon_MonitorGetTarget(Balloon *b, uint32 *target) * * Balloon_MonitorLockPage -- * - * Attempts to contact monitor and add PPN containing "addr" - * to set of "balloon locked" pages. + * Attempts to contact monitor and add PPN containing "addr" + * to set of "balloon locked" pages. * * Results: - * Returns BALLOON_SUCCESS if successful, otherwise error code. + * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1428,14 +1427,14 @@ Balloon_MonitorLockPage(Balloon *b, unsigned long addr) * * Balloon_MonitorUnlockPage -- * - * Attempts to contact monitor and remove PPN containing "addr" - * from set of "balloon locked" pages. + * Attempts to contact monitor and remove PPN containing "addr" + * from set of "balloon locked" pages. * * Results: - * Returns BALLOON_SUCCESS if successful, otherwise error code. + * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1497,18 +1496,18 @@ BalloonModuleInit(void) return(BALLOON_FAILURE); } + /* os-specific initialization */ + OS_Init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead); + /* initialize global state */ Balloon_Init(b); - /* os-specific initialization */ - os_init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead); - os_timer_init(Balloon_BH, (void *) b, os_timer_hz()); - /* start timer */ + OS_TimerInit(BalloonTimerHandler, b, OS_TimerHz()); Balloon_StartTimer(b); /* everything OK */ - return(BALLOON_SUCCESS); + return BALLOON_SUCCESS; } static void @@ -1528,8 +1527,8 @@ BalloonModuleCleanup(void) Balloon_Deallocate(b); /* os-specific cleanup */ - os_cleanup(); -} + OS_Cleanup(); +} int init_module(void) { diff --git a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_drv.c b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_drv.c index 57ef1627a..872a13c44 100644 --- a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_drv.c +++ b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_drv.c @@ -64,6 +64,12 @@ #include #include +#ifdef CONFIG_COMPAT +#ifndef HAVE_UNLOCKED_IOCTL +#include +#endif +#endif + #include "vm_basic_types.h" #include "vmnet_def.h" #include "vm_device_version.h" @@ -149,6 +155,7 @@ static unsigned int num_enable_shm; static int enable_shm[VMXNET3_SHM_MAX_DEVICES + 1] = { [0 ... VMXNET3_SHM_MAX_DEVICES] = -1 }; static char *shm_disclaimer = NULL; +static int correct_shm_disclaimer; #define VMXNET3_SHM_DISCLAIMER "IReallyWantThisModeIAmAVMSafePartner" /* @@ -909,7 +916,7 @@ vmxnet3_parse_and_copy_hdr(struct sk_buff *skb, memcpy(tdd->data, virt, ctx->copy_size); - kunmap(virt); + kunmap(VMXNET3_SHM_IDX2PAGE(adapter->shm, VMXNET3_SHM_SKB_GETIDX(skb))); } VMXNET3_LOG("copy %u bytes to dataRing[%u]\n", ctx->copy_size, tq->tx_ring.next2fill); @@ -1670,14 +1677,15 @@ vmxnet3_rx_csum(struct vmxnet3_adapter *adapter, * * vmxnet3_rx_error -- * - * called when ERR bit is set for a received pkt + * called when ERR bit is set for a received pkt. The desc and the associated + * rx buffer have not been processed yet. * * Result: * none * * Side-effects: * 1. up the stat counters - * 2. free the pkt + * 2. free the skb if needed * 3. reset ctx->skb * *---------------------------------------------------------------------------- @@ -1695,7 +1703,19 @@ vmxnet3_rx_error(struct vmxnet3_rx_queue *rq, } rq->stats.drop_total++; - vmxnet3_dev_kfree_skb_irq(adapter, ctx->skb); + /* + * We do not unmap and chain the rx buffer to the skb. + * We basically pretend this buffer is not used and will be recycled + * by vmxnet3_rq_alloc_rx_buf() + */ + + /* + * ctx->skb may be NULL if this is the first and the only one + * desc for the pkt + */ + if (ctx->skb) { + vmxnet3_dev_kfree_skb_irq(adapter, ctx->skb); + } ctx->skb = NULL; } @@ -1754,6 +1774,11 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, VMXNET3_ASSERT(rcd->len <= rxd->len); VMXNET3_ASSERT(rxd->addr == rbi->dma_addr && rxd->len == rbi->len); + if (UNLIKELY(rcd->eop && rcd->err)) { + vmxnet3_rx_error(rq, rcd, ctx, adapter); + goto rcd_done; + } + if (rcd->sop) { /* first buf of the pkt */ VMXNET3_ASSERT(rxd->btype == VMXNET3_RXD_BTYPE_HEAD && rcd->rqID == rq->qid); @@ -1793,28 +1818,16 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, rbi->page = NULL; } } else { - /* the only time a non-SOP buffer is type 0 is when it's EOP and - * error flag is raised + /* + * The only time a non-SOP buffer is type 0 is when it's EOP and + * error flag is raised, which has already been handled. */ - if (UNLIKELY(rcd->err && rcd->eop)) { - /* pretend this buffer is skipped by the device. - * dont chain it and don't reset rbi->skb to NULL - */ - VMXNET3_LOG("Err EOP is type 0 from ring[%u].rxd[%u]\n", ring_idx, idx); - } else { - /* bug in the device */ - VMXNET3_ASSERT(FALSE); - } + VMXNET3_ASSERT(FALSE); } } skb = ctx->skb; if (rcd->eop) { - if (UNLIKELY(rcd->err)) { - vmxnet3_rx_error(rq, rcd, ctx, adapter); - goto rcd_done; - } - if (adapter->is_shm) { vmxnet3_shm_rx_skb(adapter, skb); @@ -2461,7 +2474,7 @@ vmxnet3_set_mc(struct net_device *netdev) *---------------------------------------------------------------------------- */ -static int +int vmxnet3_activate_dev(struct vmxnet3_adapter *adapter) { int err; @@ -2566,7 +2579,7 @@ vmxnet3_reset_dev(struct vmxnet3_adapter *adapter) *---------------------------------------------------------------------------- */ -static int +int vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter) { if (test_and_set_bit(VMXNET3_STATE_BIT_QUIESCED, &adapter->state)) { @@ -2683,8 +2696,8 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, Bool *dma64) } #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 6) - if (pci_set_dma_mask(pdev, DMA_64BIT_MASK) == 0) { - if (pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK) != 0) { + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)) == 0) { + if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)) != 0) { printk(KERN_ERR "pci_set_consistent_dma_mask failed for adapter %s\n", compat_pci_name(pdev)); err = -EIO; @@ -2692,7 +2705,7 @@ vmxnet3_alloc_pci_resources(struct vmxnet3_adapter *adapter, Bool *dma64) } *dma64 = TRUE; } else { - if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) { + if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32)) != 0) { printk(KERN_ERR "pci_set_dma_mask failed for adapter %s\n", compat_pci_name(pdev)); err = -EIO; @@ -3060,7 +3073,7 @@ vmxnet3_close(struct net_device *netdev) * *---------------------------------------------------------------------------- */ -static void +void vmxnet3_force_close(struct vmxnet3_adapter *adapter) { /* @@ -4320,9 +4333,7 @@ vmxnet3_probe_device(struct pci_dev *pdev, adapter->is_shm = FALSE; if (adapter->dev_number < VMXNET3_SHM_MAX_DEVICES) { if (enable_shm[adapter->dev_number] == 1) { - if (shm_disclaimer == NULL || - strncmp(shm_disclaimer, VMXNET3_SHM_DISCLAIMER, - strlen(VMXNET3_SHM_DISCLAIMER)) != 0) { + if (!correct_shm_disclaimer) { printk(KERN_ERR "Did not activate shm, disclaimer missing\n"); } else { adapter->is_shm = TRUE; @@ -4629,6 +4640,21 @@ static int __init vmxnet3_init_module(void) { printk(KERN_INFO "%s - version %s\n", VMXNET3_DRIVER_DESC, VMXNET3_DRIVER_VERSION_REPORT); + + correct_shm_disclaimer = shm_disclaimer && + (strncmp(shm_disclaimer, VMXNET3_SHM_DISCLAIMER, strlen(VMXNET3_SHM_DISCLAIMER)) == 0); + +#ifdef CONFIG_COMPAT +#ifndef HAVE_UNLOCKED_IOCTL + if (correct_shm_disclaimer) { + register_ioctl32_conversion(SHM_IOCTL_TX, NULL); + register_ioctl32_conversion(SHM_IOCTL_ALLOC_ONE, NULL); + register_ioctl32_conversion(SHM_IOCTL_ALLOC_MANY, NULL); + register_ioctl32_conversion(SHM_IOCTL_ALLOC_ONE_AND_MANY, NULL); + register_ioctl32_conversion(SHM_IOCTL_FREE_ONE, NULL); + } +#endif +#endif return pci_register_driver(&vmxnet3_driver); } @@ -4652,6 +4678,17 @@ vmxnet3_init_module(void) static void vmxnet3_exit_module(void) { +#ifdef CONFIG_COMPAT +#ifndef HAVE_UNLOCKED_IOCTL + if (correct_shm_disclaimer) { + unregister_ioctl32_conversion(SHM_IOCTL_TX); + unregister_ioctl32_conversion(SHM_IOCTL_ALLOC_ONE); + unregister_ioctl32_conversion(SHM_IOCTL_ALLOC_MANY); + unregister_ioctl32_conversion(SHM_IOCTL_ALLOC_ONE_AND_MANY); + unregister_ioctl32_conversion(SHM_IOCTL_FREE_ONE); + } +#endif +#endif pci_unregister_driver(&vmxnet3_driver); } diff --git a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_int.h b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_int.h index c0c544fde..11201e67f 100644 --- a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_int.h +++ b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_int.h @@ -296,3 +296,11 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_adapter *adapter, struct net_device *netdev); +int +vmxnet3_quiesce_dev(struct vmxnet3_adapter *adapter); + +int +vmxnet3_activate_dev(struct vmxnet3_adapter *adapter); + +void +vmxnet3_force_close(struct vmxnet3_adapter *adapter); diff --git a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm.c b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm.c index eee0cf392..67c2cc534 100644 --- a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm.c +++ b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm.c @@ -290,10 +290,16 @@ static int vmxnet3_shm_chardev_release(struct inode * inode, static unsigned int vmxnet3_shm_chardev_poll(struct file *filp, poll_table *wait); -static int vmxnet3_shm_chardev_ioctl(struct inode *inode, - struct file *filp, - unsigned int cmd, - unsigned long arg); +static long vmxnet3_shm_chardev_ioctl(struct file *filp, + unsigned int cmd, + unsigned long arg); + +#ifndef HAVE_UNLOCKED_IOCTL +static int vmxnet3_shm_chardev_old_ioctl(struct inode *inode, + struct file *filp, + unsigned int cmd, + unsigned long arg); +#endif static struct file_operations shm_fops = { .owner = THIS_MODULE, @@ -301,7 +307,14 @@ static struct file_operations shm_fops = { .open = vmxnet3_shm_chardev_open, .release = vmxnet3_shm_chardev_release, .poll = vmxnet3_shm_chardev_poll, - .ioctl = vmxnet3_shm_chardev_ioctl, +#ifdef HAVE_UNLOCKED_IOCTL + .unlocked_ioctl = vmxnet3_shm_chardev_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = vmxnet3_shm_chardev_ioctl, +#endif +#else + .ioctl = vmxnet3_shm_chardev_old_ioctl, +#endif }; static LIST_HEAD(vmxnet3_shm_list); @@ -322,6 +335,88 @@ static spinlock_t vmxnet3_shm_list_lock = SPIN_LOCK_UNLOCKED; #endif +/* + *---------------------------------------------------------------------------- + * + * vmxnet3_shm_init_allocator -- + * + * Zero all shared memory data pages and fill the allocator with them. + * + * Result: + * None + * + *---------------------------------------------------------------------------- + */ + +static void +vmxnet3_shm_init_allocator(struct vmxnet3_shm_pool *shm) +{ + int i; + + shm->allocator.count = 0; + for (i = 1; i < shm->data.num_pages; i++) { + struct page *page = VMXNET3_SHM_IDX2PAGE(shm, i); + void *virt = kmap(page); + memset(virt, 0, PAGE_SIZE); + kunmap(page); + + shm->allocator.stack[shm->allocator.count++] = i; + + VMXNET3_ASSERT(i != SHM_INVALID_IDX); + } + VMXNET3_ASSERT(shm->allocator.count <= SHM_DATA_SIZE); +} + + +/* + *----------------------------------------------------------------------------- + * + * vmxnet3_shm_pool_reset -- + * + * Clean up after userspace has closed the device + * + * Results: + * None. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +static void +vmxnet3_shm_pool_reset(struct vmxnet3_shm_pool *shm) +{ + int err = 0; + printk(KERN_INFO "resetting shm pool\n"); + + /* + * Reset_work may be in the middle of resetting the device, wait for its + * completion. + */ + while (test_and_set_bit(VMXNET3_STATE_BIT_RESETTING, &shm->adapter->state)) { + compat_msleep(1); + } + + if (compat_netif_running(shm->adapter->netdev)) { + vmxnet3_quiesce_dev(shm->adapter); + } + + vmxnet3_shm_init_allocator(shm); + + if (compat_netif_running(shm->adapter->netdev)) { + err = vmxnet3_activate_dev(shm->adapter); + } + + memset(shm->ctl.ptr, 0, PAGE_SIZE); + + clear_bit(VMXNET3_STATE_BIT_RESETTING, &shm->adapter->state); + + if (err) { + vmxnet3_force_close(shm->adapter); + } +} + /* *----------------------------------------------------------------------------- * @@ -367,29 +462,15 @@ vmxnet3_shm_pool_create(struct vmxnet3_adapter *adapter, // Allocate data pages shm->data.num_pages = SHM_DATA_SIZE; for (i = 1; i < shm->data.num_pages; i++) { -#ifdef __GFP_ZERO - struct page *page = alloc_page(GFP_KERNEL|__GFP_ZERO); -#else struct page *page = alloc_page(GFP_KERNEL); -#endif if (page == NULL) { goto fail_data; } -#ifndef __GFP_ZERO - { - void *virt = kmap(page); - memset(virt, 0, PAGE_SIZE); - kunmap(virt); - } -#endif - VMXNET3_SHM_SET_IDX2PAGE(shm, i, page); - shm->allocator.stack[shm->allocator.count++] = i; VMXNET3_ASSERT(i != SHM_INVALID_IDX); } - VMXNET3_ASSERT(shm->allocator.count <= SHM_DATA_SIZE); // Allocate control page ctl_page = alloc_page(GFP_KERNEL); @@ -397,10 +478,13 @@ vmxnet3_shm_pool_create(struct vmxnet3_adapter *adapter, goto fail_ctl; } ctl_ptr = (void*)kmap(ctl_page); - memset(ctl_ptr, 0, PAGE_SIZE); shm->ctl.pages[0] = ctl_page; shm->ctl.ptr = ctl_ptr; + // Reset data and control pages + vmxnet3_shm_init_allocator(shm); + memset(shm->ctl.ptr, 0, PAGE_SIZE); + // Register char device shm->misc_dev.minor = MISC_DYNAMIC_MINOR; shm->misc_dev.name = shm->name; @@ -480,7 +564,6 @@ vmxnet3_shm_pool_release(struct kobject *kobj) // Free data pages for (i = 1; i < SHM_DATA_SIZE; i++) { - kunmap(VMXNET3_SHM_IDX2PAGE(shm,i)); __free_page(VMXNET3_SHM_IDX2PAGE(shm, i)); } @@ -774,7 +857,13 @@ vmxnet3_shm_chardev_poll(struct file *filp, struct vmxnet3_shm_ringentry *re; // consume TX queue - vmxnet3_shm_consume_user_tx_queue(shm); + if (vmxnet3_shm_consume_user_tx_queue(shm) == -1) { + // the device has been closed, let the user space + // know there is activity, so that it gets a chance + // to read the channelBad flag. + mask |= POLLIN; + return mask; + } // Wait on the rxq for an interrupt to wake us poll_wait(filp, &shm->rxq, wait); @@ -808,9 +897,8 @@ vmxnet3_shm_chardev_poll(struct file *filp, *----------------------------------------------------------------------------- */ -static int -vmxnet3_shm_chardev_ioctl(struct inode *inode, - struct file *filp, +static long +vmxnet3_shm_chardev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -827,11 +915,7 @@ vmxnet3_shm_chardev_ioctl(struct inode *inode, case SHM_IOCTL_ALLOC_ONE: idx = vmxnet3_shm_alloc_page(shm); - if (idx != SHM_INVALID_IDX) { - return idx; - } else { - return -ENOMEM; - } + return idx; case SHM_IOCTL_ALLOC_MANY: for (i = 0; i < arg; i++) { @@ -839,10 +923,10 @@ vmxnet3_shm_chardev_ioctl(struct inode *inode, if (idx != SHM_INVALID_IDX) { if (vmxnet3_shm_user_rx(shm, idx, 0, 1, 1)) { vmxnet3_shm_free_page(shm, idx); - return -ENOMEM; + return SHM_INVALID_IDX; } } else { - return -ENOMEM; + return SHM_INVALID_IDX; } } return 0; @@ -850,7 +934,7 @@ vmxnet3_shm_chardev_ioctl(struct inode *inode, case SHM_IOCTL_ALLOC_ONE_AND_MANY: idx1 = vmxnet3_shm_alloc_page(shm); if (idx1 == SHM_INVALID_IDX) { - return -ENOMEM; + return SHM_INVALID_IDX; } for (i = 0; i < arg - 1; i++) { idx = vmxnet3_shm_alloc_page(shm); @@ -858,11 +942,11 @@ vmxnet3_shm_chardev_ioctl(struct inode *inode, if (vmxnet3_shm_user_rx(shm, idx, 0, 1, 1)) { vmxnet3_shm_free_page(shm, idx); vmxnet3_shm_free_page(shm, idx1); - return -ENOMEM; + return SHM_INVALID_IDX; } } else { vmxnet3_shm_free_page(shm, idx1); - return -ENOMEM; + return SHM_INVALID_IDX; } } return idx1; @@ -877,6 +961,15 @@ vmxnet3_shm_chardev_ioctl(struct inode *inode, return -ENOTTY; } +#ifndef HAVE_UNLOCKED_IOCTL +static int vmxnet3_shm_chardev_old_ioctl(struct inode *inode, + struct file *filp, + unsigned int cmd, + unsigned long arg) +{ + return vmxnet3_shm_chardev_ioctl(filp, cmd, arg); +} +#endif /* *----------------------------------------------------------------------------- @@ -974,9 +1067,15 @@ vmxnet3_shm_chardev_release(struct inode * inode, struct file * filp) { struct vmxnet3_shm_pool *shm = filp->private_data; - kobject_put(&shm->kobj); - // XXX: I guess we should reset the control pages here + if (shm->adapter) { + vmxnet3_shm_pool_reset(shm); + } else { + vmxnet3_shm_init_allocator(shm); + memset(shm->ctl.ptr, 0, PAGE_SIZE); + } + + kobject_put(&shm->kobj); return 0; } @@ -1070,6 +1169,9 @@ vmxnet3_shm_tx_pkt(struct vmxnet3_adapter *adapter, skb = dev_alloc_skb(100); if (skb == NULL) { + for (i = 0; i < frags; i++) { + vmxnet3_shm_free_page(adapter->shm, res[i].idx); + } VMXNET3_ASSERT(FALSE); return -ENOMEM; } @@ -1131,8 +1233,6 @@ static int vmxnet3_shm_tx_re(struct vmxnet3_shm_pool *shm, struct vmxnet3_shm_ringentry re) { - int i; - shm->partial_tx.res[shm->partial_tx.frags++] = re; if (re.eop) { @@ -1140,9 +1240,7 @@ vmxnet3_shm_tx_re(struct vmxnet3_shm_pool *shm, shm->partial_tx.res, shm->partial_tx.frags); if (status < 0) { - for (i = 0; i < shm->partial_tx.frags; i++) { - vmxnet3_shm_free_page(shm, shm->partial_tx.res[i].idx); - } + VMXNET3_LOG("vmxnet3_shm_tx_pkt failed %d\n", status); } shm->partial_tx.frags = 0; return 1; @@ -1414,6 +1512,12 @@ vmxnet3_shm_close(struct vmxnet3_adapter *adapter) adapter->shm->adapter = NULL; spin_unlock_irqrestore(&adapter->shm->tx_lock, flags); + // Mark the channel as 'in bad state' + adapter->shm->ctl.ptr->channelBad = 1; + kobject_put(&adapter->shm->kobj); + + wake_up(&adapter->shm->rxq); + return 0; } diff --git a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm_shared.h b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm_shared.h index e3eca683d..a838d51e7 100644 --- a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm_shared.h +++ b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_shm_shared.h @@ -52,8 +52,8 @@ #define SHM_CTL_SIZE 1 // ring size (in entries) is limited by the single control page - 4 bytes per re -#define SHM_RX_RING_SIZE 507 -#define SHM_TX_RING_SIZE 507 +#define SHM_RX_RING_SIZE 500 +#define SHM_TX_RING_SIZE 500 // maximum fragments per packet is 16 (64k) + 2 for metadata #define VMXNET3_SHM_MAX_FRAGS 18 @@ -86,6 +86,8 @@ struct vmxnet3_shm_ctl uint64_t user_rx, user_tx; uint64_t kernel_rx, kernel_tx; } stats; + + uint64_t channelBad; }; #endif diff --git a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_version.h b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_version.h index f3c0891c9..03b9dff64 100644 --- a/open-vm-tools/modules/linux/vmxnet3/vmxnet3_version.h +++ b/open-vm-tools/modules/linux/vmxnet3/vmxnet3_version.h @@ -25,11 +25,11 @@ #ifndef _VMXNET3_VERSION_H_ #define _VMXNET3_VERSION_H_ -#define VMXNET3_DRIVER_VERSION 1.0.1.0 -#define VMXNET3_DRIVER_VERSION_COMMAS 1,0,1,0 -#define VMXNET3_DRIVER_VERSION_STRING "1.0.1.0" +#define VMXNET3_DRIVER_VERSION 1.0.3.0 +#define VMXNET3_DRIVER_VERSION_COMMAS 1,0,3,0 +#define VMXNET3_DRIVER_VERSION_STRING "1.0.3.0" /* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */ -#define VMXNET3_DRIVER_VERSION_NUM 0x01000100 +#define VMXNET3_DRIVER_VERSION_NUM 0x01000300 #endif /* _VMXNET3_VERSION_H_ */ diff --git a/open-vm-tools/modules/linux/vsock/linux/af_vsock.c b/open-vm-tools/modules/linux/vsock/linux/af_vsock.c index d152b5db0..c2b2febb4 100644 --- a/open-vm-tools/modules/linux/vsock/linux/af_vsock.c +++ b/open-vm-tools/modules/linux/vsock/linux/af_vsock.c @@ -103,21 +103,13 @@ #include #include #include +#include #include #if defined(__x86_64__) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) -# if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) -# include -# else -# include -# endif +# include /* Use weak: not all kernels export sys_ioctl for use by modules */ -# if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 66) asmlinkage __attribute__((weak)) long sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); -# else -asmlinkage __attribute__((weak)) int -sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); -# endif #endif #include "compat_module.h" @@ -146,6 +138,9 @@ sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); #include "vsock_version.h" #include "driverLog.h" +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) +# error "Linux kernels before 2.6.9 are not supported." +#endif #define VSOCK_INVALID_FAMILY NPROTO #define VSOCK_AF_IS_REGISTERED(val) ((val) >= 0 && (val) < NPROTO) @@ -162,6 +157,9 @@ sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg); int VSockVmci_GetAFValue(void); /* Internal functions. */ +static Bool VSockVmciProtoToNotifyStruct(struct sock *sk, + VSockProtoVersion *proto, + Bool oldPktProto); static int VSockVmciGetAFValue(void); static int VSockVmciRecvDgramCB(void *data, VMCIDatagram *dg); static int VSockVmciRecvStreamCB(void *data, VMCIDatagram *dg); @@ -176,6 +174,8 @@ static int VSockVmciRecvConnectingServer(struct sock *sk, static int VSockVmciRecvConnectingClient(struct sock *sk, VSockPacket *pkt); static int VSockVmciRecvConnectingClientNegotiate(struct sock *sk, VSockPacket *pkt); +static int VSockVmciRecvConnectingClientInvalid(struct sock *sk, + VSockPacket *pkt); static int VSockVmciRecvConnected(struct sock *sk, VSockPacket *pkt); static int __VSockVmciBind(struct sock *sk, struct sockaddr_vm *addr); #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 14) @@ -216,38 +216,6 @@ static int VSockVmciStreamSetsockopt(struct socket *sock, int level, int optname static int VSockVmciStreamGetsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user * optlen); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43) -static int VSockVmciDgramSendmsg(struct socket *sock, struct msghdr *msg, - int len, struct scm_cookie *scm); -static int VSockVmciDgramRecvmsg(struct socket *sock, struct msghdr *msg, - int len, int flags, struct scm_cookie *scm); -static int VSockVmciStreamSendmsg(struct socket *sock, struct msghdr *msg, - int len, struct scm_cookie *scm); -static int VSockVmciStreamRecvmsg(struct socket *sock, struct msghdr *msg, - int len, int flags, struct scm_cookie *scm); -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65) -static int VSockVmciDgramSendmsg(struct kiocb *kiocb, struct socket *sock, - struct msghdr *msg, int len, - struct scm_cookie *scm); -static int VSockVmciDgramRecvmsg(struct kiocb *kiocb, struct socket *sock, - struct msghdr *msg, int len, - int flags, struct scm_cookie *scm); -static int VSockVmciStreamSendmsg(struct kiocb *kiocb, struct socket *sock, - struct msghdr *msg, int len, - struct scm_cookie *scm); -static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, struct socket *sock, - struct msghdr *msg, int len, - int flags, struct scm_cookie *scm); -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2) -static int VSockVmciDgramSendmsg(struct kiocb *kiocb, - struct socket *sock, struct msghdr *msg, int len); -static int VSockVmciDgramRecvmsg(struct kiocb *kiocb, struct socket *sock, - struct msghdr *msg, int len, int flags); -static int VSockVmciStreamSendmsg(struct kiocb *kiocb, - struct socket *sock, struct msghdr *msg, int len); -static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, struct socket *sock, - struct msghdr *msg, int len, int flags); -#else static int VSockVmciDgramSendmsg(struct kiocb *kiocb, struct socket *sock, struct msghdr *msg, size_t len); static int VSockVmciDgramRecvmsg(struct kiocb *kiocb, struct socket *sock, @@ -256,7 +224,6 @@ static int VSockVmciStreamSendmsg(struct kiocb *kiocb, struct socket *sock, struct msghdr *msg, size_t len); static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, struct socket *sock, struct msghdr *msg, size_t len, int flags); -#endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) static int VSockVmciCreate(struct socket *sock, int protocol); @@ -280,8 +247,7 @@ static long VSockVmciDevUnlockedIoctl(struct file *filp, * Variables. */ -/* Protocol family. We only use this for builds against 2.6.9 and later. */ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 9) +/* Protocol family. */ static struct proto vsockVmciProto = { .name = "AF_VMCI", #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10) @@ -289,38 +255,31 @@ static struct proto vsockVmciProto = { .owner = THIS_MODULE, #endif /* - * Before 2.6.9, each address family created their own slab (by calling - * kmem_cache_create() directly). From 2.6.9 until 2.6.11, these address - * families instead called sk_alloc_slab() and the allocated slab was - * assigned to the slab variable in the proto struct and was created of size - * slab_obj_size. As of 2.6.12 and later, this slab allocation was moved - * into proto_register() and only done if you specified a non-zero value for + * From 2.6.9 until 2.6.11, these address families called sk_alloc_slab() + * and the allocated slab was assigned to the slab variable in the proto + * struct and was created of size slab_obj_size. + * As of 2.6.12 and later, this slab allocation was moved into + * proto_register() and only done if you specified a non-zero value for * the second argument (alloc_slab); the size of the slab element was * changed to obj_size. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) .slab_obj_size = sizeof (VSockVmciSock), #else .obj_size = sizeof (VSockVmciSock), #endif }; -#endif static struct net_proto_family vsockVmciFamilyOps = { .family = VSOCK_INVALID_FAMILY, .create = VSockVmciCreate, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 69) .owner = THIS_MODULE, -#endif }; /* Socket operations, split for DGRAM and STREAM sockets. */ static struct proto_ops vsockVmciDgramOps = { .family = VSOCK_INVALID_FAMILY, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 69) .owner = THIS_MODULE, -#endif .release = VSockVmciRelease, .bind = VSockVmciBind, .connect = VSockVmciDgramConnect, @@ -336,16 +295,12 @@ static struct proto_ops vsockVmciDgramOps = { .sendmsg = VSockVmciDgramSendmsg, .recvmsg = VSockVmciDgramRecvmsg, .mmap = sock_no_mmap, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) .sendpage = sock_no_sendpage, -#endif }; static struct proto_ops vsockVmciStreamOps = { .family = VSOCK_INVALID_FAMILY, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 69) .owner = THIS_MODULE, -#endif .release = VSockVmciRelease, .bind = VSockVmciBind, .connect = VSockVmciStreamConnect, @@ -361,9 +316,7 @@ static struct proto_ops vsockVmciStreamOps = { .sendmsg = VSockVmciStreamSendmsg, .recvmsg = VSockVmciStreamRecvmsg, .mmap = sock_no_mmap, -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 4, 4) .sendpage = sock_no_sendpage, -#endif }; static struct file_operations vsockVmciDeviceOps = { @@ -401,11 +354,7 @@ static Bool vmciDevicePresent = FALSE; static VMCIHandle vmciStreamHandle = { VMCI_INVALID_ID, VMCI_INVALID_ID }; static VMCIId qpResumedSubId = VMCI_INVALID_ID; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 5) -kmem_cache_t *vsockCachep; -#endif -#endif +static int protocolOverride = -1; /* * 64k is hopefully a reasonable default, but we should do some real @@ -422,6 +371,125 @@ kmem_cache_t *vsockCachep; #endif +/* + *---------------------------------------------------------------------------- + * + * VSockVmciOldProtoOverride -- + * + * Check to see if the user has asked us to override all sockets to use + * the vsock notify protocol. + * + * Results: + * TRUE if there is a protocol override in effect. + * - oldPktProto is TRUE the original protocol should be used. + * FALSE if there is no override in effect. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static Bool +VSockVmciOldProtoOverride(Bool *oldPktProto) // IN +{ + ASSERT(oldPktProto); + + if (protocolOverride != -1) { + if (protocolOverride == 0) { + *oldPktProto = TRUE; + } else { + *oldPktProto = FALSE; + } + Warning("Proto override in use.\n"); + return TRUE; + } + + return FALSE; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciProtoToNotifyStruct -- + * + * Given a particular notify protocol version, setup the socket's notify + * struct correctly. + * + * Results: + * TRUE on success. FALSE otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static Bool +VSockVmciProtoToNotifyStruct(struct sock *sk, // IN + VSockProtoVersion *proto, // IN + Bool oldPktProto) // IN +{ + VSockVmciSock *vsk; + + ASSERT(sk); + ASSERT(proto); + + vsk = vsock_sk(sk); + + if (oldPktProto) { + if (*proto != VSOCK_PROTO_INVALID) { + Warning("Can't set both an old and new protocol\n"); + return FALSE; + } + vsk->notifyOps = &vSockVmciNotifyPktOps; + goto exit; + } + + switch(*proto) { + case VSOCK_PROTO_PKT_ON_NOTIFY: + vsk->notifyOps= &vSockVmciNotifyPktQStateOps; + break; + default: + Warning("Unknown notify protocol version\n"); + return FALSE; + } + +exit: + NOTIFYCALL(vsk, socketInit, sk); + return TRUE; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNewProtoSupportedVersions + * + * Gets the supported REQUEST2/NEGOTIATE2 vsock protocol versions. + * + * Results: + * Either 1 specific protocol version (override mode) or + * VSOCK_PROTO_ALL_SUPPORTED. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static VSockProtoVersion +VSockVmciNewProtoSupportedVersions(void) // IN +{ + if (protocolOverride != -1) { + return protocolOverride; + } + + return VSOCK_PROTO_ALL_SUPPORTED; +} + + /* *---------------------------------------------------------------------------- * @@ -929,11 +997,9 @@ VSockVmciRecvStreamCB(void *data, // IN * when implementing backwards compatibility in the future. */ if (pkt->type >= VSOCK_PACKET_TYPE_MAX) { - if (VSOCK_SEND_INVALID_BH(&dst, &src) < 0) { - Warning("unable to send reply for invalid packet.\n"); - err = VMCI_ERROR_INVALID_ARGS; - goto out; - } + VSOCK_SEND_INVALID_BH(&dst, &src); + err = VMCI_ERROR_INVALID_ARGS; + goto out; } /* @@ -1097,9 +1163,7 @@ VSockVmciHandleDetach(struct sock *sk) // IN * receive, but we can still receive if there is data left in our consume * queue. */ - sk->compat_sk_shutdown |= SEND_SHUTDOWN; if (VSockVmciStreamHasData(vsk) <= 0) { - sk->compat_sk_shutdown |= RCV_SHUTDOWN; sk->compat_sk_state = SS_UNCONNECTED; } sk->compat_sk_state_change(sk); @@ -1390,6 +1454,8 @@ VSockVmciRecvListen(struct sock *sk, // IN VSockVmciSock *vpending; int err; uint64 qpSize; + Bool oldRequest = FALSE; + Bool oldPktProto = FALSE; ASSERT(sk); ASSERT(pkt); @@ -1431,10 +1497,16 @@ VSockVmciRecvListen(struct sock *sk, // IN * The listen state only accepts connection requests. Reply with a reset * unless we received a reset. */ - if (pkt->type != VSOCK_PACKET_TYPE_REQUEST || - pkt->u.size == 0) { - VSOCK_REPLY_RESET(pkt); - return -EINVAL; + + if (!(pkt->type == VSOCK_PACKET_TYPE_REQUEST || + pkt->type == VSOCK_PACKET_TYPE_REQUEST2)) { + VSOCK_REPLY_RESET(pkt); + return -EINVAL; + } + + if (pkt->u.size == 0) { + VSOCK_REPLY_RESET(pkt); + return -EINVAL; } /* @@ -1474,13 +1546,61 @@ VSockVmciRecvListen(struct sock *sk, // IN * it. Otherwise propose our own size. */ if (pkt->u.size >= vsk->queuePairMinSize && - pkt->u.size <= vsk->queuePairMaxSize) { + pkt->u.size <= vsk->queuePairMaxSize) { qpSize = pkt->u.size; } else { qpSize = vsk->queuePairSize; } - err = VSOCK_SEND_NEGOTIATE(pending, qpSize); + /* + * Figure out if we are using old or new requests based on the overrides + * pkt types sent by our peer. + */ + if (VSockVmciOldProtoOverride(&oldPktProto)) { + oldRequest = oldPktProto; + } else { + if (pkt->type == VSOCK_PACKET_TYPE_REQUEST) { + oldRequest = TRUE; + } else if (pkt->type == VSOCK_PACKET_TYPE_REQUEST2) { + oldRequest = FALSE; + } + } + + if (oldRequest) { + /* Handle a REQUEST (or override) */ + VSockProtoVersion version = VSOCK_PROTO_INVALID; + if (VSockVmciProtoToNotifyStruct(pending, &version, TRUE)) { + err = VSOCK_SEND_NEGOTIATE(pending, qpSize); + } else { + err = -EINVAL; + } + } else { + /* Handle a REQUEST2 (or override) */ + int protoInt = pkt->proto; + int pos; + uint16 activeProtoVersion = 0; + + /* + * The list of possible protocols is the intersection of all protocols + * the client supports ... plus all the protocols we support. + */ + protoInt &= VSockVmciNewProtoSupportedVersions(); + + /* We choose the highest possible protocol version and use that one. */ + pos = fls(protoInt); + if (pos) { + activeProtoVersion = (1 << (pos - 1)); + if (VSockVmciProtoToNotifyStruct(pending, &activeProtoVersion, FALSE)) { + err = VSOCK_SEND_NEGOTIATE2(pending, qpSize, + activeProtoVersion); + } else { + err = -EINVAL; + } + } else { + err = -EINVAL; + } + } + if (err < 0) { VSOCK_SEND_RESET(sk, pkt); sock_put(pending); @@ -1494,8 +1614,7 @@ VSockVmciRecvListen(struct sock *sk, // IN pending->compat_sk_state = SS_CONNECTING; vpending->produceSize = vpending->consumeSize = qpSize; - /* XXX Move this into the notify file. */ - vpending->notify.writeNotifyWindow = qpSize; + NOTIFYCALL(vpending, processRequest, pending); /* * We might never receive another message for this socket and it's not @@ -1738,8 +1857,10 @@ VSockVmciRecvConnectingClient(struct sock *sk, // IN: socket sk->compat_sk_socket->state = SS_CONNECTED; VSockVmciInsertConnected(vsockConnectedSocketsVsk(vsk), sk); sk->compat_sk_state_change(sk); + break; case VSOCK_PACKET_TYPE_NEGOTIATE: + case VSOCK_PACKET_TYPE_NEGOTIATE2: if (pkt->u.size == 0 || VMCI_HANDLE_TO_CONTEXT_ID(pkt->dg.src) != vsk->remoteAddr.svm_cid || pkt->srcPort != vsk->remoteAddr.svm_port || @@ -1761,11 +1882,34 @@ VSockVmciRecvConnectingClient(struct sock *sk, // IN: socket goto destroy; } + break; + case VSOCK_PACKET_TYPE_INVALID: + err = VSockVmciRecvConnectingClientInvalid(sk, pkt); + if (err) { + skerr = -err; + goto destroy; + } + break; case VSOCK_PACKET_TYPE_RST: - skerr = ECONNRESET; - err = 0; - goto destroy; + /* + * Older versions of the linux code (WS 6.5 / ESX 4.0) used to continue + * processing here after they sent an INVALID packet. This meant that we + * got a RST after the INVALID. We ignore a RST after an INVALID. The + * common code doesn't send the RST ... so we can hang if an old version + * of the common code fails between getting a REQUEST and sending an + * OFFER back. Not much we can do about it... except hope that it + * doesn't happen. + */ + if (vsk->ignoreConnectingRst) { + vsk->ignoreConnectingRst = FALSE; + } else { + skerr = ECONNRESET; + err = 0; + goto destroy; + } + + break; default: /* Close and cleanup the connection. */ skerr = EPROTO; @@ -1774,7 +1918,10 @@ VSockVmciRecvConnectingClient(struct sock *sk, // IN: socket } ASSERT(pkt->type == VSOCK_PACKET_TYPE_ATTACH || - pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE); + pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE || + pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE2 || + pkt->type == VSOCK_PACKET_TYPE_INVALID || + pkt->type == VSOCK_PACKET_TYPE_RST); return 0; @@ -1819,6 +1966,10 @@ VSockVmciRecvConnectingClientNegotiate(struct sock *sk, // IN: socket VMCIId attachSubId; VMCIId detachSubId; Bool isLocal; + uint32 flags; + Bool oldProto = TRUE; + Bool oldPktProto; + VSockProtoVersion version; vsk = vsock_sk(sk); handle = VMCI_INVALID_HANDLE; @@ -1838,6 +1989,13 @@ VSockVmciRecvConnectingClientNegotiate(struct sock *sk, // IN: socket ASSERT(vsk->attachSubId == VMCI_INVALID_ID); ASSERT(vsk->detachSubId == VMCI_INVALID_ID); + /* + * If we have gotten here then we should be past the point where old linux + * vsock could have sent the bogus rst. + */ + vsk->sentRequest = FALSE; + vsk->ignoreConnectingRst = FALSE; + /* Verify that we're OK with the proposed queue pair size */ if (pkt->u.size < vsk->queuePairMinSize || pkt->u.size > vsk->queuePairMaxSize) { @@ -1845,6 +2003,32 @@ VSockVmciRecvConnectingClientNegotiate(struct sock *sk, // IN: socket goto destroy; } + /* + * Setup the notify ops to be the highest supported version that both the + * server and the client support. + */ + + if (VSockVmciOldProtoOverride(&oldPktProto)) { + oldProto = oldPktProto; + } else { + if (pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE) { + oldProto = TRUE; + } else if (pkt->type == VSOCK_PACKET_TYPE_NEGOTIATE2) { + oldProto = FALSE; + } + } + + if (oldProto) { + version = VSOCK_PROTO_INVALID; + } else { + version = pkt->proto; + } + + if (!VSockVmciProtoToNotifyStruct(sk, &version, oldProto)) { + err = -EINVAL; + goto destroy; + } + /* * Subscribe to attach and detach events first. * @@ -1873,12 +2057,13 @@ VSockVmciRecvConnectingClientNegotiate(struct sock *sk, // IN: socket /* Make VMCI select the handle for us. */ handle = VMCI_INVALID_HANDLE; isLocal = vsk->remoteAddr.svm_cid == vsk->localAddr.svm_cid; + flags = isLocal ? VMCI_QPFLAG_LOCAL : 0; err = VSockVmciQueuePairAlloc(&handle, &produceQ, pkt->u.size, &consumeQ, pkt->u.size, vsk->remoteAddr.svm_cid, - isLocal ? VMCI_QPFLAG_LOCAL : 0, + flags, vsk->trusted); if (err < 0) { goto destroy; @@ -1898,12 +2083,11 @@ VSockVmciRecvConnectingClientNegotiate(struct sock *sk, // IN: socket vsk->produceSize = vsk->consumeSize = pkt->u.size; - /* XXX Move this into the notify file. */ - vsk->notify.writeNotifyWindow = pkt->u.size; - vsk->attachSubId = attachSubId; vsk->detachSubId = detachSubId; + NOTIFYCALL(vsk, processNegotiate, sk); + return 0; destroy: @@ -1926,6 +2110,52 @@ destroy: } +/* + *---------------------------------------------------------------------------- + * + * VSockVmciRecvConnectingClientInvalid -- + * + * Handles an invalid packet for a client in the connecting state. + * + * Note that this assumes the socket lock is held for both sk and pending. + * + * Results: + * Zero on success, negative error code on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +VSockVmciRecvConnectingClientInvalid(struct sock *sk, // IN: socket + VSockPacket *pkt) // IN: current packet +{ + int err = 0; + VSockVmciSock *vsk; + + ASSERT(sk); + ASSERT(pkt); + + vsk = vsock_sk(sk); + + if (vsk->sentRequest) { + vsk->sentRequest = FALSE; + vsk->ignoreConnectingRst = TRUE; + + err = VSOCK_SEND_CONN_REQUEST(sk, vsk->queuePairSize); + if (err < 0) { + err = VSockVmci_ErrorToVSockError(err); + } else { + err = 0; + } + } + + return err; +} + + /* *---------------------------------------------------------------------------- * @@ -1977,7 +2207,7 @@ VSockVmciRecvConnected(struct sock *sk, // IN switch (pkt->type) { case VSOCK_PACKET_TYPE_SHUTDOWN: if (pkt->u.mode) { - VSockVmciSock *vsk = vsock_sk(sk); + vsk = vsock_sk(sk); vsk->peerShutdown |= pkt->u.mode; sk->compat_sk_state_change(sk); @@ -1998,10 +2228,8 @@ VSockVmciRecvConnected(struct sock *sk, // IN */ compat_sock_set_done(sk); vsk->peerShutdown = SHUTDOWN_MASK; - sk->compat_sk_shutdown |= SEND_SHUTDOWN; if (VSockVmciStreamHasData(vsk) <= 0) { sk->compat_sk_state = SS_DISCONNECTING; - sk->compat_sk_shutdown = SHUTDOWN_MASK; } sk->compat_sk_state_change(sk); break; @@ -2046,6 +2274,7 @@ __VSockVmciSendControlPkt(VSockPacket *pkt, // IN uint64 size, // IN uint64 mode, // IN VSockWaitingInfo *wait, // IN + VSockProtoVersion proto, // IN VMCIHandle handle, // IN Bool convertError) // IN { @@ -2060,7 +2289,7 @@ __VSockVmciSendControlPkt(VSockPacket *pkt, // IN VSOCK_ADDR_NOFAMILY_ASSERT(src); VSOCK_ADDR_NOFAMILY_ASSERT(dst); - VSockPacket_Init(pkt, src, dst, type, size, mode, wait, handle); + VSockPacket_Init(pkt, src, dst, type, size, mode, wait, proto, handle); LOG_PACKET(pkt); VSOCK_STATS_CTLPKT_LOG(pkt->type); err = VMCIDatagram_Send(&pkt->dg); @@ -2107,7 +2336,8 @@ VSockVmciReplyControlPktFast(VSockPacket *pkt, // IN } else { VSockPacket_GetAddresses(pkt, &src, &dst); return __VSockVmciSendControlPkt(&reply, &src, &dst, type, - size, mode, wait, handle, TRUE); + size, mode, wait, + VSOCK_PROTO_INVALID, handle, TRUE); } } @@ -2149,7 +2379,8 @@ VSockVmciSendControlPktBH(struct sockaddr_vm *src, // IN static VSockPacket pkt; return __VSockVmciSendControlPkt(&pkt, src, dst, type, - size, mode, wait, handle, FALSE); + size, mode, wait, VSOCK_PROTO_INVALID, + handle, FALSE); } @@ -2170,12 +2401,13 @@ VSockVmciSendControlPktBH(struct sockaddr_vm *src, // IN */ int -VSockVmciSendControlPkt(struct sock *sk, // IN - VSockPacketType type, // IN - uint64 size, // IN - uint64 mode, // IN - VSockWaitingInfo *wait, // IN - VMCIHandle handle) // IN +VSockVmciSendControlPkt(struct sock *sk, // IN + VSockPacketType type, // IN + uint64 size, // IN + uint64 mode, // IN + VSockWaitingInfo *wait, // IN + VSockProtoVersion proto, // IN + VMCIHandle handle) // IN { VSockPacket *pkt; VSockVmciSock *vsk; @@ -2206,7 +2438,8 @@ VSockVmciSendControlPkt(struct sock *sk, // IN } err = __VSockVmciSendControlPkt(pkt, &vsk->localAddr, &vsk->remoteAddr, - type, size, mode, wait, handle, TRUE); + type, size, mode, wait, proto, handle, + TRUE); kfree(pkt); return err; @@ -2339,7 +2572,11 @@ __VSockVmciBind(struct sock *sk, // IN/OUT goto out; } - VSockAddr_Init(&vsk->localAddr, newAddr.svm_cid, newAddr.svm_port); + /* + * VSockVmci_GetAFValue() acquires a mutex and may sleep, so fill the + * field after unlocking socket tables. + */ + VSockAddr_InitNoFamily(&vsk->localAddr, newAddr.svm_cid, newAddr.svm_port); /* * Remove stream sockets from the unbound list and add them to the hash @@ -2349,9 +2586,12 @@ __VSockVmciBind(struct sock *sk, // IN/OUT if (sk->compat_sk_socket->type == SOCK_STREAM) { __VSockVmciRemoveBound(sk); __VSockVmciInsertBound(vsockBoundSockets(&vsk->localAddr), sk); + spin_unlock_bh(&vsockTableLock); } + vsk->localAddr.svm_family = VSockVmci_GetAFValue(); + VSOCK_ADDR_ASSERT(&vsk->localAddr); - err = 0; + return 0; out: if (sk->compat_sk_socket->type == SOCK_STREAM) { @@ -2412,25 +2652,14 @@ __VSockVmciCreate(struct net *net, // IN: Network namespace vsk = NULL; /* - * Before 2.5.5, sk_alloc() always used its own cache and protocol-specific - * data was contained in the protinfo union. We cannot use those other - * structures so we allocate our own structure and attach it to the - * user_data pointer that we don't otherwise need. We must be sure to free - * it later in our destruct routine. - * - * From 2.5.5 until 2.6.8, sk_alloc() offerred to use a cache that the - * caller provided. After this, the cache was moved into the proto - * structure, but you still had to specify the size and cache yourself until - * 2.6.12. Most recently (in 2.6.24), sk_alloc() was changed to expect the + * From 2.6.9 to until 2.6.12 sk_alloc() used a cache in + * the protocol structure, but you still had to specify the size and cache + * yourself. + * Most recently (in 2.6.24), sk_alloc() was changed to expect the * network namespace, and the option to zero the sock was dropped. * */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5) - sk = sk_alloc(vsockVmciFamilyOps.family, priority, 1); -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) - sk = sk_alloc(vsockVmciFamilyOps.family, priority, - sizeof (VSockVmciSock), vsockCachep); -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) sk = sk_alloc(vsockVmciFamilyOps.family, priority, vsockVmciProto.slab_obj_size, vsockVmciProto.slab); #elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) @@ -2442,15 +2671,6 @@ __VSockVmciCreate(struct net *net, // IN: Network namespace return NULL; } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5) - vsock_sk(sk) = kmalloc(sizeof *vsk, priority); - if (!vsock_sk(sk)) { - sk_free(sk); - return NULL; - } - sk_vsock(vsock_sk(sk)) = sk; -#endif - /* * If we go this far, we know the socket family is registered, so there's no * need to register it now. @@ -2492,6 +2712,8 @@ __VSockVmciCreate(struct net *net, // IN: Network namespace INIT_LIST_HEAD(&vsk->pendingLinks); INIT_LIST_HEAD(&vsk->acceptQueue); vsk->rejected = FALSE; + vsk->sentRequest = FALSE; + vsk->ignoreConnectingRst = FALSE; vsk->attachSubId = vsk->detachSubId = VMCI_INVALID_ID; vsk->peerShutdown = 0; @@ -2502,8 +2724,7 @@ __VSockVmciCreate(struct net *net, // IN: Network namespace vsk->trusted = capable(CAP_NET_ADMIN); } - vsk->notifyOps = &vSockVmciNotifyPktOps; - NOTIFYCALL(vsk, socketInit, sk); + vsk->notifyOps = NULL; if (sock) { VSockVmciInsertBound(vsockUnboundSockets, sk); @@ -2637,11 +2858,6 @@ VSockVmciSkDestruct(struct sock *sk) // IN NOTIFYCALL(vsk, socketDestruct, sk); -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5) - ASSERT(vsock_sk(sk) == vsk); - kfree(vsock_sk(sk)); -#endif - down(®istrationMutex); vsockVmciSocketCount--; VSockVmciTestUnregister(); @@ -2650,7 +2866,6 @@ VSockVmciSkDestruct(struct sock *sk) // IN VSOCK_STATS_CTLPKT_DUMP_ALL(); VSOCK_STATS_HIST_DUMP_ALL(); - } @@ -2707,24 +2922,15 @@ VSockVmciRegisterProto(void) int err = 0; /* - * Before 2.6.9, each address family created their own slab (by calling - * kmem_cache_create() directly). From 2.6.9 until 2.6.11, these address - * families instead called sk_alloc_slab() and the allocated slab was - * assigned to the slab variable in the proto struct and was created of size - * slab_obj_size. As of 2.6.12 and later, this slab allocation was moved - * into proto_register() and only done if you specified a non-zero value for - * the second argument (alloc_slab); the size of the slab element was + * From 2.6.9 until 2.6.11, these address families called sk_alloc_slab() + * and the allocated slab was assigned to the slab variable in the proto + * struct and was created of size slab_obj_size. As of 2.6.12 and later, + * this slab allocation was moved + * into proto_register() and only done if you specified a non-zero value + * for the second argument (alloc_slab); the size of the slab element was * changed to obj_size. */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5) - /* Simply here for clarity and so else case at end implies > rest. */ -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) - vsockCachep = kmem_cache_create("vsock", sizeof (VSockVmciSock), - 0, SLAB_HWCACHE_ALIGN, NULL, NULL); - if (!vsockCachep) { - err = -ENOMEM; - } -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) err = sk_alloc_slab(&vsockVmciProto, "vsock"); if (err != 0) { sk_alloc_slab_error(&vsockVmciProto); @@ -2757,11 +2963,7 @@ VSockVmciRegisterProto(void) static void VSockVmciUnregisterProto(void) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 5) - /* Simply here for clarity and so else case at end implies > rest. */ -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 9) - kmem_cache_destroy(vsockCachep); -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) +#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 12) sk_free_slab(&vsockVmciProto); #else proto_unregister(&vsockVmciProto); @@ -3149,6 +3351,7 @@ VSockVmciStreamConnect(struct socket *sock, // IN VSockVmciSock *vsk; struct sockaddr_vm *remoteAddr; long timeout; + Bool oldPktProto = FALSE; COMPAT_DEFINE_WAIT(wait); err = 0; @@ -3205,10 +3408,22 @@ VSockVmciStreamConnect(struct socket *sock, // IN sk->compat_sk_state = SS_CONNECTING; - err = VSOCK_SEND_CONN_REQUEST(sk, vsk->queuePairSize); - if (err < 0) { - sk->compat_sk_state = SS_UNCONNECTED; - goto out; + if (VSockVmciOldProtoOverride(&oldPktProto) && oldPktProto) { + err = VSOCK_SEND_CONN_REQUEST(sk, vsk->queuePairSize); + if (err < 0) { + sk->compat_sk_state = SS_UNCONNECTED; + goto out; + } + } else { + int supportedProtoVersions = VSockVmciNewProtoSupportedVersions(); + err = VSOCK_SEND_CONN_REQUEST2(sk, vsk->queuePairSize, + supportedProtoVersions); + if (err < 0) { + sk->compat_sk_state = SS_UNCONNECTED; + goto out; + } + + vsk->sentRequest = TRUE; } /* @@ -3476,13 +3691,20 @@ VSockVmciPoll(struct file *file, // IN mask |= POLLERR; } - if (sk->compat_sk_shutdown == SHUTDOWN_MASK) { + /* + * INET sockets treat local write shutdown and peer write shutdown + * as a case of POLLHUP set. + */ + if ((sk->compat_sk_shutdown == SHUTDOWN_MASK) || + ((sk->compat_sk_shutdown & SEND_SHUTDOWN) && + (vsk->peerShutdown & SEND_SHUTDOWN))) { mask |= POLLHUP; } /* POLLRDHUP wasn't added until 2.6.17. */ #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 17) - if (sk->compat_sk_shutdown & RCV_SHUTDOWN) { + if (sk->compat_sk_shutdown & RCV_SHUTDOWN || + vsk->peerShutdown & SEND_SHUTDOWN) { mask |= POLLRDHUP; } #endif @@ -3547,17 +3769,29 @@ VSockVmciPoll(struct file *file, // IN if (!(sk->compat_sk_shutdown & SEND_SHUTDOWN)) { Bool spaceAvailNow = FALSE; int32 ret = 0; + NOTIFYCALLRET(vsk, ret, pollOut, sk, 1, &spaceAvailNow); if (ret < 0) { mask |= POLLERR; } else { if (spaceAvailNow) { - mask |= POLLOUT | POLLWRNORM | POLLWRBAND; + /* Remove POLLWRBAND since INET sockets are not setting it.*/ + mask |= POLLOUT | POLLWRNORM; } } } } + /* + * Simulate INET socket poll behaviors, which sets POLLOUT|POLLWRNORM when + * peer is closed and nothing to read, but local send is not shutdown. + */ + if (sk->compat_sk_state == SS_UNCONNECTED) { + if (!(sk->compat_sk_shutdown & SEND_SHUTDOWN)) { + mask |= POLLOUT | POLLWRNORM; + } + } + release_sock(sk); } @@ -3697,32 +3931,11 @@ VSockVmciShutdown(struct socket *sock, // IN *---------------------------------------------------------------------------- */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43) -static int -VSockVmciDgramSendmsg(struct socket *sock, // IN: socket to send on - struct msghdr *msg, // IN: message to send - int len, // IN: length of message - struct scm_cookie *scm) // UNUSED -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65) -static int -VSockVmciDgramSendmsg(struct kiocb *kiocb, // UNUSED - struct socket *sock, // IN: socket to send on - struct msghdr *msg, // IN: message to send - int len, // IN: length of message - struct scm_cookie *scm); // UNUSED -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2) -static int -VSockVmciDgramSendmsg(struct kiocb *kiocb, // UNUSED - struct socket *sock, // IN: socket to send on - struct msghdr *msg, // IN: message to send - int len) // IN: length of message -#else static int VSockVmciDgramSendmsg(struct kiocb *kiocb, // UNUSED struct socket *sock, // IN: socket to send on struct msghdr *msg, // IN: message to send size_t len) // IN: length of message -#endif { int err; struct sock *sk; @@ -4008,32 +4221,11 @@ VSockVmciStreamGetsockopt(struct socket *sock, // IN *---------------------------------------------------------------------------- */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43) -static int -VSockVmciStreamSendmsg(struct socket *sock, // IN: socket to send on - struct msghdr *msg, // IN: message to send - int len, // IN: length of message - struct scm_cookie *scm) // UNUSED -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65) -static int -VSockVmciStreamSendmsg(struct kiocb *kiocb, // UNUSED - struct socket *sock, // IN: socket to send on - struct msghdr *msg, // IN: message to send - int len, // IN: length of message - struct scm_cookie *scm); // UNUSED -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2) -static int -VSockVmciStreamSendmsg(struct kiocb *kiocb, // UNUSED - struct socket *sock, // IN: socket to send on - struct msghdr *msg, // IN: message to send - int len) // IN: length of message -#else static int VSockVmciStreamSendmsg(struct kiocb *kiocb, // UNUSED struct socket *sock, // IN: socket to send on struct msghdr *msg, // IN: message to send size_t len) // IN: length of message -#endif { struct sock *sk; VSockVmciSock *vsk; @@ -4061,7 +4253,9 @@ VSockVmciStreamSendmsg(struct kiocb *kiocb, // UNUSED goto out; } - if (sk->compat_sk_shutdown & SEND_SHUTDOWN) { + /* Send data only if both sides are not shutdown in the direction. */ + if (sk->compat_sk_shutdown & SEND_SHUTDOWN || + vsk->peerShutdown & RCV_SHUTDOWN) { err = -EPIPE; goto out; } @@ -4109,6 +4303,7 @@ VSockVmciStreamSendmsg(struct kiocb *kiocb, // UNUSED } NOTIFYCALLRET(vsk, err, sendPreBlock, sk, &sendData); + if (err < 0) { goto outWait; } @@ -4200,36 +4395,12 @@ out: *---------------------------------------------------------------------------- */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43) -static int -VSockVmciDgramRecvmsg(struct socket *sock, // IN: socket to receive from - struct msghdr *msg, // IN/OUT: message to receive into - int len, // IN: length of receive buffer - int flags, // IN: receive flags - struct scm_cookie *scm) // UNUSED -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65) -static int -VSockVmciDgramRecvmsg(struct kiocb *kiocb, // UNUSED - struct socket *sock, // IN: socket to receive from - struct msghdr *msg, // IN/OUT: message to receive into - int len, // IN: length of receive buffer - int flags, // IN: receive flags - struct scm_cookie *scm) // UNUSED -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2) -static int -VSockVmciDgramRecvmsg(struct kiocb *kiocb, // UNUSED - struct socket *sock, // IN: socket to receive from - struct msghdr *msg, // IN/OUT: message to receive into - int len, // IN: length of receive buffer - int flags) // IN: receive flags -#else static int VSockVmciDgramRecvmsg(struct kiocb *kiocb, // UNUSED struct socket *sock, // IN: socket to receive from struct msghdr *msg, // IN/OUT: message to receive into size_t len, // IN: length of receive buffer int flags) // IN: receive flags -#endif { int err; int noblock; @@ -4315,36 +4486,12 @@ out: *---------------------------------------------------------------------------- */ -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 43) -static int -VSockVmciStreamRecvmsg(struct socket *sock, // IN: socket to receive from - struct msghdr *msg, // IN/OUT: message to receive into - int len, // IN: length of receive buffer - int flags, // IN: receive flags - struct scm_cookie *scm) // UNUSED -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 65) -static int -VSockVmciStreamRecvmsg(struct kiocb *kiocb, // UNUSED - struct socket *sock, // IN: socket to receive from - struct msghdr *msg, // IN/OUT: message to receive into - int len, // IN: length of receive buffer - int flags, // IN: receive flags - struct scm_cookie *scm) // UNUSED -#elif LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 2) -static int -VSockVmciStreamRecvmsg(struct kiocb *kiocb, // UNUSED - struct socket *sock, // IN: socket to receive from - struct msghdr *msg, // IN/OUT: message to receive into - int len, // IN: length of receive buffer - int flags) // IN: receive flags -#else static int VSockVmciStreamRecvmsg(struct kiocb *kiocb, // UNUSED struct socket *sock, // IN: socket to receive from struct msghdr *msg, // IN/OUT: message to receive into size_t len, // IN: length of receive buffer int flags) // IN: receive flags -#endif { struct sock *sk; VSockVmciSock *vsk; @@ -4383,6 +4530,10 @@ VSockVmciStreamRecvmsg(struct kiocb *kiocb, // UNUSED goto out; } + /* + * We don't check peerShutdown flag here since peer may actually shut down, + * but there can be data in the VMCI queue that local socket can receive. + */ if (sk->compat_sk_shutdown & RCV_SHUTDOWN) { err = 0; goto out; @@ -4492,12 +4643,10 @@ VSockVmciStreamRecvmsg(struct kiocb *kiocb, // UNUSED /* * If the other side has shutdown for sending and there is nothing more to - * read, then set our socket's RCV_SHUTDOWN flag and modify the socket - * state. + * read, then modify the socket state. */ if (vsk->peerShutdown & SEND_SHUTDOWN) { if (VSockVmciStreamHasData(vsk) <= 0) { - sk->compat_sk_shutdown |= RCV_SHUTDOWN; sk->compat_sk_state = SS_UNCONNECTED; compat_sock_set_done(sk); sk->compat_sk_state_change(sk); @@ -4607,18 +4756,10 @@ VSockVmciIoctl32Handler(unsigned int fd, // IN struct file * filp) // IN { int ret; -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 26) || \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3)) - lock_kernel(); -#endif ret = -ENOTTY; if (filp && filp->f_op && filp->f_op->ioctl == VSockVmciDevIoctl) { ret = VSockVmciDevIoctl(filp->f_dentry->d_inode, filp, iocmd, ioarg); } -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 4, 26) || \ - (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 5, 0) && LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 3)) - unlock_kernel(); -#endif return ret; } #endif /* !HAVE_COMPAT_IOCTL */ @@ -4935,6 +5076,7 @@ MODULE_AUTHOR("VMware, Inc."); MODULE_DESCRIPTION("VMware Virtual Socket Family"); MODULE_VERSION(VSOCK_DRIVER_VERSION_STRING); MODULE_LICENSE("GPL v2"); + /* * Starting with SLE10sp2, Novell requires that IHVs sign a support agreement * with them and mark their kernel modules as externally supported via a @@ -4942,3 +5084,9 @@ MODULE_LICENSE("GPL v2"); * by default (i.e., neither mkinitrd nor modprobe will accept it). */ MODULE_INFO(supported, "external"); + +#ifdef VMX86_DEVEL +/* We only support protocol negotiation overrides on devel builds. */ +module_param(protocolOverride, int, 0); +MODULE_PARM_DESC(protocolOverride, "Specify a vsock protocol (auto negotiated by default"); +#endif diff --git a/open-vm-tools/modules/linux/vsock/linux/af_vsock.h b/open-vm-tools/modules/linux/vsock/linux/af_vsock.h index f66a914a2..85f971467 100644 --- a/open-vm-tools/modules/linux/vsock/linux/af_vsock.h +++ b/open-vm-tools/modules/linux/vsock/linux/af_vsock.h @@ -93,6 +93,8 @@ typedef struct VSockVmciSock { Bool rejected; compat_delayed_work dwork; uint32 peerShutdown; + Bool sentRequest; + Bool ignoreConnectingRst; } VSockVmciSock; int VSockVmciSendControlPktBH(struct sockaddr_vm *src, @@ -107,7 +109,9 @@ int VSockVmciReplyControlPktFast(VSockPacket *pkt, VSockPacketType type, VSockWaitingInfo *wait, VMCIHandle handle); int VSockVmciSendControlPkt(struct sock *sk, VSockPacketType type, uint64 size, uint64 mode, - VSockWaitingInfo *wait, VMCIHandle handle); + VSockWaitingInfo *wait, + VSockProtoVersion version, + VMCIHandle handle); int64 VSockVmciStreamHasData(VSockVmciSock *vsk); int64 VSockVmciStreamHasSpace(VSockVmciSock *vsk); @@ -130,34 +134,50 @@ int64 VSockVmciStreamHasSpace(VSockVmciSock *vsk); ((_pkt)->type == VSOCK_PACKET_TYPE_RST) ? \ 0 : \ VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_RST, \ - 0, 0, NULL, VMCI_INVALID_HANDLE) + 0, 0, NULL, VSOCK_PROTO_INVALID, \ + VMCI_INVALID_HANDLE) #define VSOCK_SEND_NEGOTIATE(_sk, _size) \ VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_NEGOTIATE, \ - _size, 0, NULL, VMCI_INVALID_HANDLE) + _size, 0, NULL, VSOCK_PROTO_INVALID, \ + VMCI_INVALID_HANDLE) +#define VSOCK_SEND_NEGOTIATE2(_sk, _size, signalProto) \ + VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_NEGOTIATE2, \ + _size, 0, NULL, signalProto, \ + VMCI_INVALID_HANDLE) #define VSOCK_SEND_QP_OFFER(_sk, _handle) \ VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_OFFER, \ - 0, 0, NULL, _handle) + 0, 0, NULL, VSOCK_PROTO_INVALID, _handle) #define VSOCK_SEND_CONN_REQUEST(_sk, _size) \ VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_REQUEST, \ - _size, 0, NULL, VMCI_INVALID_HANDLE) + _size, 0, NULL, VSOCK_PROTO_INVALID, \ + VMCI_INVALID_HANDLE) +#define VSOCK_SEND_CONN_REQUEST2(_sk, _size, signalProto) \ + VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_REQUEST2, \ + _size, 0, NULL, signalProto, \ + VMCI_INVALID_HANDLE) #define VSOCK_SEND_ATTACH(_sk, _handle) \ VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_ATTACH, \ - 0, 0, NULL, _handle) + 0, 0, NULL, VSOCK_PROTO_INVALID, _handle) #define VSOCK_SEND_WROTE(_sk) \ VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_WROTE, \ - 0, 0, NULL, VMCI_INVALID_HANDLE) + 0, 0, NULL, VSOCK_PROTO_INVALID, \ + VMCI_INVALID_HANDLE) #define VSOCK_SEND_READ(_sk) \ VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_READ, \ - 0, 0, NULL, VMCI_INVALID_HANDLE) + 0, 0, NULL, VSOCK_PROTO_INVALID, \ + VMCI_INVALID_HANDLE) #define VSOCK_SEND_SHUTDOWN(_sk, _mode) \ VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_SHUTDOWN, \ - 0, _mode, NULL, VMCI_INVALID_HANDLE) + 0, _mode, NULL, VSOCK_PROTO_INVALID, \ + VMCI_INVALID_HANDLE) #define VSOCK_SEND_WAITING_WRITE(_sk, _waitInfo) \ VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_WAITING_WRITE, \ - 0, 0, _waitInfo, VMCI_INVALID_HANDLE) + 0, 0, _waitInfo, VSOCK_PROTO_INVALID, \ + VMCI_INVALID_HANDLE) #define VSOCK_SEND_WAITING_READ(_sk, _waitInfo) \ VSockVmciSendControlPkt(_sk, VSOCK_PACKET_TYPE_WAITING_READ, \ - 0, 0, _waitInfo, VMCI_INVALID_HANDLE) + 0, 0, _waitInfo, VSOCK_PROTO_INVALID, \ + VMCI_INVALID_HANDLE) #define VSOCK_REPLY_RESET(_pkt) \ VSockVmciReplyControlPktFast(_pkt, VSOCK_PACKET_TYPE_RST, \ 0, 0, NULL, VMCI_INVALID_HANDLE) diff --git a/open-vm-tools/modules/linux/vsock/linux/notify.c b/open-vm-tools/modules/linux/vsock/linux/notify.c index 81f0ce0ba..858773495 100644 --- a/open-vm-tools/modules/linux/vsock/linux/notify.c +++ b/open-vm-tools/modules/linux/vsock/linux/notify.c @@ -33,7 +33,7 @@ #include "af_vsock.h" #define PKT_FIELD(vsk, fieldName) \ - (vsk)->notify.fieldName + (vsk)->notify.pkt.fieldName #define VSOCK_MAX_DGRAM_RESENDS 10 @@ -1124,6 +1124,65 @@ VSockVmciNotifyPktHandlePkt(struct sock *sk, // IN } } + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNotifyPktProcessRequest + * + * Called near the end of process request. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static void +VSockVmciNotifyPktProcessRequest(struct sock *sk) // IN +{ + VSockVmciSock *vsk; + + ASSERT(sk); + + vsk = vsock_sk(sk); + + PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNotifyPktProcessNegotiate + * + * Called near the end of process negotiate. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static void +VSockVmciNotifyPktProcessNegotiate(struct sock *sk) // IN +{ + VSockVmciSock *vsk; + + ASSERT(sk); + + vsk = vsock_sk(sk); + + PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize; +} + + /* Socket control packet based operations. */ VSockVmciNotifyOps vSockVmciNotifyPktOps = { VSockVmciNotifyPktSocketInit, @@ -1138,5 +1197,7 @@ VSockVmciNotifyOps vSockVmciNotifyPktOps = { VSockVmciNotifyPktSendInit, VSockVmciNotifyPktSendPreBlock, VSockVmciNotifyPktSendPreEnqueue, - VSockVmciNotifyPktSendPostEnqueue + VSockVmciNotifyPktSendPostEnqueue, + VSockVmciNotifyPktProcessRequest, + VSockVmciNotifyPktProcessNegotiate, }; diff --git a/open-vm-tools/modules/linux/vsock/linux/notify.h b/open-vm-tools/modules/linux/vsock/linux/notify.h index e07346e53..bf91adc18 100644 --- a/open-vm-tools/modules/linux/vsock/linux/notify.h +++ b/open-vm-tools/modules/linux/vsock/linux/notify.h @@ -36,9 +36,12 @@ # define VSOCK_OPTIMIZATION_FLOW_CONTROL 1 #endif +#define VSOCK_MAX_DGRAM_RESENDS 10 + #define NOTIFYCALLRET(vsk, rv, mod_fn, args...) \ do { \ - if (vsk->notifyOps->mod_fn != NULL) { \ + if (vsk->notifyOps && \ + vsk->notifyOps->mod_fn != NULL) { \ rv = (vsk->notifyOps->mod_fn)(args); \ } else { \ rv = 0; \ @@ -47,13 +50,13 @@ do { \ #define NOTIFYCALL(vsk, mod_fn, args...) \ do { \ - if (vsk->notifyOps->mod_fn != NULL) { \ + if (vsk->notifyOps && \ + vsk->notifyOps->mod_fn != NULL) { \ (vsk->notifyOps->mod_fn)(args); \ } \ } while (0) - -typedef struct VSockVmciNotify { +typedef struct VSockVmciNotifyPkt { uint64 writeNotifyWindow; uint64 writeNotifyMinWindow; Bool peerWaitingRead; @@ -65,23 +68,29 @@ typedef struct VSockVmciNotify { VSockWaitingInfo peerWaitingWriteInfo; uint64 produceQGeneration; uint64 consumeQGeneration; +} VSockVmciNotifyPkt; + +typedef struct VSockVmciNotifyPktQState { + uint64 writeNotifyWindow; + uint64 writeNotifyMinWindow; + Bool peerWaitingWrite; + Bool peerWaitingWriteDetected; +} VSockVmciNotifyPktQState; + +typedef union VSockVmciNotify { + VSockVmciNotifyPkt pkt; + VSockVmciNotifyPktQState pktQState; } VSockVmciNotify; typedef struct VSockVmciRecvNotifyData { -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) uint64 consumeHead; uint64 produceTail; -#ifdef VSOCK_OPTIMIZATION_FLOW_CONTROL Bool notifyOnBlock; -#endif -#endif } VSockVmciRecvNotifyData; typedef struct VSockVmciSendNotifyData { -#if defined(VSOCK_OPTIMIZATION_WAITING_NOTIFY) uint64 consumeHead; uint64 produceTail; -#endif } VSockVmciSendNotifyData; /* Socket notification callbacks. */ @@ -110,8 +119,11 @@ typedef struct VSockVmciNotifyOps { int32 (*sendPostEnqueue)(struct sock *sk, ssize_t written, VSockVmciSendNotifyData *data); + void (*processRequest)(struct sock *sk); + void (*processNegotiate)(struct sock *sk); } VSockVmciNotifyOps; extern VSockVmciNotifyOps vSockVmciNotifyPktOps; +extern VSockVmciNotifyOps vSockVmciNotifyPktQStateOps; #endif /* __NOTIFY_H__ */ diff --git a/open-vm-tools/modules/linux/vsock/linux/notifyQState.c b/open-vm-tools/modules/linux/vsock/linux/notifyQState.c new file mode 100644 index 000000000..bee549e42 --- /dev/null +++ b/open-vm-tools/modules/linux/vsock/linux/notifyQState.c @@ -0,0 +1,788 @@ +/********************************************************* + * Copyright (C) 2009 VMware, Inc. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation version 2 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 GNU General Public License + * for more details. + * + * You should have received a copy of the GNU 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 + * + *********************************************************/ + +/* + * notifyQState.c -- + * + * Linux control notifications based on Queuepair state for the VMCI + * Stream Sockets protocol. + */ + + +#include "driver-config.h" + +#include + +#include "compat_sock.h" + +#include "notify.h" +#include "af_vsock.h" + +#define PKT_FIELD(vsk, fieldName) \ + (vsk)->notify.pktQState.fieldName + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNotifyWaitingWrite -- + * + * Determines if the conditions have been met to notify a waiting writer. + * + * Results: + * TRUE if a notification should be sent, FALSE otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static Bool +VSockVmciNotifyWaitingWrite(VSockVmciSock *vsk) // IN +{ + Bool retval; + uint64 notifyLimit; + + if (!PKT_FIELD(vsk, peerWaitingWrite)) { + return FALSE; + } + + /* + * When the sender blocks, we take that as a sign that the sender + * is faster than the receiver. To reduce the transmit rate of the + * sender, we delay the sending of the read notification by + * decreasing the writeNotifyWindow. The notification is delayed + * until the number of bytes used in the queue drops below the + * writeNotifyWindow. + */ + + if (!PKT_FIELD(vsk, peerWaitingWriteDetected)) { + PKT_FIELD(vsk, peerWaitingWriteDetected) = TRUE; + PKT_FIELD(vsk, writeNotifyWindow) -= PAGE_SIZE; + if (PKT_FIELD(vsk, writeNotifyWindow) < + PKT_FIELD(vsk, writeNotifyMinWindow)) { + PKT_FIELD(vsk, writeNotifyWindow) = + PKT_FIELD(vsk, writeNotifyMinWindow); + } + } + notifyLimit = vsk->consumeSize - PKT_FIELD(vsk, writeNotifyWindow); + + /* + * The notifyLimit is used to delay notifications in the case where + * flow control is enabled. Below the test is expressed in terms of + * free space in the queue: + * if freeSpace > ConsumeSize - writeNotifyWindow then notify + * An alternate way of expressing this is to rewrite the expression + * to use the data ready in the receive queue: + * if writeNotifyWindow > bufferReady then notify + * as freeSpace == ConsumeSize - bufferReady. + */ + + retval = VMCIQueue_FreeSpace(vsk->consumeQ, vsk->produceQ, vsk->consumeSize) > + notifyLimit; + + if (retval) { + /* + * Once we notify the peer, we reset the detected flag so the + * next wait will again cause a decrease in the window size. + */ + + PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE; + } + return retval; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciHandleRead -- + * + * Handles an incoming read message. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static void +VSockVmciHandleRead(struct sock *sk, // IN + VSockPacket *pkt, // IN: unused + Bool bottomHalf, // IN: unused + struct sockaddr_vm *dst, // IN: unused + struct sockaddr_vm *src) // IN: unused +{ + + sk->compat_sk_write_space(sk); +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciHandleWrote -- + * + * Handles an incoming wrote message. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static void +VSockVmciHandleWrote(struct sock *sk, // IN + VSockPacket *pkt, // IN: unused + Bool bottomHalf, // IN: unused + struct sockaddr_vm *dst, // IN: unused + struct sockaddr_vm *src) // IN: unused +{ + sk->compat_sk_data_ready(sk, 0); +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciBlockUpdateWriteWindow -- + * + * Updates the write window when we are blocking for data. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static void +VSockVmciBlockUpdateWriteWindow(struct sock *sk) // IN +{ + VSockVmciSock *vsk; + + vsk = vsock_sk(sk); + + if (PKT_FIELD(vsk, writeNotifyWindow) < vsk->consumeSize) { + PKT_FIELD(vsk, writeNotifyWindow) = + MIN(PKT_FIELD(vsk, writeNotifyWindow) + PAGE_SIZE, + vsk->consumeSize); + } +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciSendReadNotification -- + * + * Sends a read notification to this socket's peer. + * + * Results: + * >= 0 if the datagram is sent successfully, negative error value + * otherwise. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int +VSockVmciSendReadNotification(struct sock *sk) // IN +{ + VSockVmciSock *vsk; + Bool sentRead; + unsigned int retries; + int err; + + ASSERT(sk); + + vsk = vsock_sk(sk); + sentRead = FALSE; + retries = 0; + err = 0; + + if (VSockVmciNotifyWaitingWrite(vsk)) { + /* + * Notify the peer that we have read, retrying the send on failure up to our + * maximum value. XXX For now we just log the failure, but later we should + * schedule a work item to handle the resend until it succeeds. That would + * require keeping track of work items in the vsk and cleaning them up upon + * socket close. + */ + while (!(vsk->peerShutdown & RCV_SHUTDOWN) && + !sentRead && + retries < VSOCK_MAX_DGRAM_RESENDS) { + err = VSOCK_SEND_READ(sk); + if (err >= 0) { + sentRead = TRUE; + } + + retries++; + } + + if (retries >= VSOCK_MAX_DGRAM_RESENDS && !sentRead) { + Warning("unable to send read notification to peer for socket %p.\n", sk); + } else { + PKT_FIELD(vsk, peerWaitingWrite) = FALSE; + } + } + return err; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNotifyPktSocketInit -- + * + * Function that is called after a socket is created and before any + * notify ops are used. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static void +VSockVmciNotifyPktSocketInit(struct sock *sk) // IN +{ + VSockVmciSock *vsk; + vsk = vsock_sk(sk); + + PKT_FIELD(vsk, writeNotifyWindow) = 0; + PKT_FIELD(vsk, writeNotifyMinWindow) = PAGE_SIZE; + PKT_FIELD(vsk, peerWaitingWrite) = FALSE; + PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNotifyPktSocketDestruct -- + * + * Function that is called when the socket is being released. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static void +VSockVmciNotifyPktSocketDestruct(struct sock *sk) // IN +{ + VSockVmciSock *vsk; + vsk = vsock_sk(sk); + + PKT_FIELD(vsk, writeNotifyWindow) = 0; + PKT_FIELD(vsk, writeNotifyMinWindow) = PAGE_SIZE; + PKT_FIELD(vsk, peerWaitingWrite) = FALSE; + PKT_FIELD(vsk, peerWaitingWriteDetected) = FALSE; + return; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNotifyPktPollIn -- + * + * Called by the poll function to figure out if there is data to read + * and to setup future notifications if needed. Only called on sockets + * that aren't shutdown for recv. + * + * Results: + * 0 on success. Negative error on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int32 +VSockVmciNotifyPktPollIn(struct sock *sk, // IN + int target, // IN + Bool *dataReadyNow) // IN +{ + VSockVmciSock *vsk; + + ASSERT(sk); + ASSERT(dataReadyNow); + + vsk = vsock_sk(sk); + + if (VSockVmciStreamHasData(vsk)) { + *dataReadyNow = TRUE; + } else { + /* + * We can't read right now because there is nothing in the queue. + * Ask for notifications when there is something to read. + */ + if (sk->compat_sk_state == SS_CONNECTED) { + VSockVmciBlockUpdateWriteWindow(sk); + } + *dataReadyNow = FALSE; + } + + return 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNotifyPktPollOut + * + * Called by the poll function to figure out if there is space to write + * and to setup future notifications if needed. Only called on a + * connected socket that isn't shutdown for send. + * + * Results: + * 0 on success. Negative error on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int32 +VSockVmciNotifyPktPollOut(struct sock *sk, // IN + int target, // IN + Bool *spaceAvailNow) // IN +{ + int64 produceQFreeSpace; + VSockVmciSock *vsk; + + ASSERT(sk); + ASSERT(spaceAvailNow); + + vsk = vsock_sk(sk); + + produceQFreeSpace = + VSockVmciStreamHasSpace(vsk); + if (produceQFreeSpace > 0) { + *spaceAvailNow = TRUE; + return 0; + } else if (produceQFreeSpace == 0) { + /* + * This is a connected socket but we can't currently send data. Nothing + * else to do. + */ + *spaceAvailNow = FALSE; + } + + return 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNotifyPktRecvInit -- + * + * Called at the start of a stream recv call with the socket lock held. + * + * Results: + * 0 on success. Negative error on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int32 +VSockVmciNotifyPktRecvInit(struct sock *sk, // IN + int target, // IN + VSockVmciRecvNotifyData *data) // IN +{ + VSockVmciSock *vsk; + + ASSERT(sk); + ASSERT(data); + + vsk = vsock_sk(sk); + + data->consumeHead = 0; + data->produceTail = 0; + data->notifyOnBlock = FALSE; + + if (PKT_FIELD(vsk, writeNotifyMinWindow) < target + 1) { + ASSERT(target < vsk->consumeSize); + PKT_FIELD(vsk, writeNotifyMinWindow) = target + 1; + if (PKT_FIELD(vsk, writeNotifyWindow) < + PKT_FIELD(vsk, writeNotifyMinWindow)) { + /* + * If the current window is smaller than the new minimal + * window size, we need to reevaluate whether we need to + * notify the sender. If the number of ready bytes are + * smaller than the new window, we need to send a + * notification to the sender before we block. + */ + + PKT_FIELD(vsk, writeNotifyWindow) = + PKT_FIELD(vsk, writeNotifyMinWindow); + data->notifyOnBlock = TRUE; + } + } + + return 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNotifyPktRecvPreBlock -- + * + * Called right before a socket is about to block with the socket lock + * held. The socket lock may have been released between the entry + * function and the preblock call. + * + * Note: This function may be called multiple times before the post + * block function is called. + * + * Results: + * 0 on success. Negative error on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int32 +VSockVmciNotifyPktRecvPreBlock(struct sock *sk, // IN + int target, // IN + VSockVmciRecvNotifyData *data) // IN +{ + VSockVmciSock *vsk; + int err; + + ASSERT(sk); + ASSERT(data); + + vsk = vsock_sk(sk); + err = 0; + + VSockVmciBlockUpdateWriteWindow(sk); + + if (data->notifyOnBlock) { + err = VSockVmciSendReadNotification(sk); + if (err < 0) { + return err; + } + data->notifyOnBlock = FALSE; + } + + return err; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNotifyPktRecvPostDequeue -- + * + * Called right after we dequeue / peek data from a socket. + * + * Results: + * 0 on success. Negative error on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int32 +VSockVmciNotifyPktRecvPostDequeue(struct sock *sk, // IN + int target, // IN + ssize_t copied, // IN + Bool dataRead, // IN + VSockVmciRecvNotifyData *data) // IN +{ + VSockVmciSock *vsk; + int err; + Bool wasFull = FALSE; + uint64 freeSpace; + + ASSERT(sk); + ASSERT(data); + + vsk = vsock_sk(sk); + err = 0; + + if (dataRead) { + Atomic_MFence(); + + freeSpace = VMCIQueue_FreeSpace(vsk->consumeQ, + vsk->produceQ, + vsk->consumeSize); + wasFull = freeSpace == copied; + + if (wasFull) { + PKT_FIELD(vsk, peerWaitingWrite) = TRUE; + } + + err = VSockVmciSendReadNotification(sk); + if (err < 0) { + return err; + } + + /* See the comment in VSockVmciNotifyPktSendPostEnqueue */ + sk->compat_sk_data_ready(sk, 0); + } + + return err; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNotifyPktSendInit -- + * + * Called at the start of a stream send call with the socket lock held. + * + * Results: + * 0 on success. A negative error code on failure. + * + * Side effects: + * + *---------------------------------------------------------------------------- + */ + +static int32 +VSockVmciNotifyPktSendInit(struct sock *sk, // IN + VSockVmciSendNotifyData *data) // IN +{ + ASSERT(sk); + ASSERT(data); + + data->consumeHead = 0; + data->produceTail = 0; + + return 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNotifySendPostEnqueue -- + * + * Called right after we enqueue data to a socket. + * + * Results: + * 0 on success. Negative error on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static int32 +VSockVmciNotifyPktSendPostEnqueue(struct sock *sk, // IN + ssize_t written, // IN + VSockVmciSendNotifyData *data) // IN +{ + int err = 0; + VSockVmciSock *vsk; + Bool sentWrote = FALSE; + Bool wasEmpty; + + int retries = 0; + + ASSERT(sk); + ASSERT(data); + + vsk = vsock_sk(sk); + + Atomic_MFence(); + + wasEmpty = (VMCIQueue_BufReady(vsk->produceQ, + vsk->consumeQ, + vsk->produceSize) == written); + if (wasEmpty) { + while (!(vsk->peerShutdown & RCV_SHUTDOWN) && + !sentWrote && + retries < VSOCK_MAX_DGRAM_RESENDS) { + err = VSOCK_SEND_WROTE(sk); + if (err >= 0) { + sentWrote = TRUE; + } + + retries++; + } + } + + if (retries >= VSOCK_MAX_DGRAM_RESENDS && !sentWrote) { + Warning("unable to send wrote notification to peer for socket %p.\n", sk); + return err; + } + + return err; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNotifyPktHandlePkt + * + * Called when a notify packet is recieved for a socket in the connected + * state. Note this might be called from a bottom half. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static void +VSockVmciNotifyPktHandlePkt(struct sock *sk, // IN + VSockPacket *pkt, // IN + Bool bottomHalf, // IN + struct sockaddr_vm *dst, // IN + struct sockaddr_vm *src, // IN + Bool *pktProcessed) // In +{ + Bool processed = FALSE; + + ASSERT(sk); + ASSERT(pkt); + + switch (pkt->type) { + case VSOCK_PACKET_TYPE_WROTE: + VSockVmciHandleWrote(sk, pkt, bottomHalf, dst, src); + processed = TRUE; + break; + case VSOCK_PACKET_TYPE_READ: + VSockVmciHandleRead(sk, pkt, bottomHalf, dst, src); + processed = TRUE; + break; + } + + if (pktProcessed) { + *pktProcessed = processed; + } +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNotifyPktProcessRequest + * + * Called near the end of process request. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static void +VSockVmciNotifyPktProcessRequest(struct sock *sk) // IN +{ + VSockVmciSock *vsk; + + ASSERT(sk); + + vsk = vsock_sk(sk); + + PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize; +} + + +/* + *---------------------------------------------------------------------------- + * + * VSockVmciNotifyPktProcessNegotiate + * + * Called near the end of process negotiate. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static void +VSockVmciNotifyPktProcessNegotiate(struct sock *sk) // IN +{ + VSockVmciSock *vsk; + + ASSERT(sk); + + vsk = vsock_sk(sk); + + PKT_FIELD(vsk, writeNotifyWindow) = vsk->consumeSize; +} + + +/* Socket always on control packet based operations. */ +VSockVmciNotifyOps vSockVmciNotifyPktQStateOps = { + VSockVmciNotifyPktSocketInit, + VSockVmciNotifyPktSocketDestruct, + VSockVmciNotifyPktPollIn, + VSockVmciNotifyPktPollOut, + VSockVmciNotifyPktHandlePkt, + VSockVmciNotifyPktRecvInit, + VSockVmciNotifyPktRecvPreBlock, + NULL, /* recvPreDequeue */ + VSockVmciNotifyPktRecvPostDequeue, + VSockVmciNotifyPktSendInit, + NULL, /* sendPreBlock */ + NULL, /* sendPreEnqueue */ + VSockVmciNotifyPktSendPostEnqueue, + VSockVmciNotifyPktProcessRequest, + VSockVmciNotifyPktProcessNegotiate, +}; diff --git a/open-vm-tools/modules/linux/vsock/linux/util.c b/open-vm-tools/modules/linux/vsock/linux/util.c index 53f2edb8e..932885655 100644 --- a/open-vm-tools/modules/linux/vsock/linux/util.c +++ b/open-vm-tools/modules/linux/vsock/linux/util.c @@ -83,6 +83,8 @@ VSockVmciLogPkt(char const *function, // IN [VSOCK_PACKET_TYPE_SHUTDOWN] = "SHUTDOWN", [VSOCK_PACKET_TYPE_WAITING_WRITE] = "WAITING_WRITE", [VSOCK_PACKET_TYPE_WAITING_READ] = "WAITING_READ", + [VSOCK_PACKET_TYPE_REQUEST2] = "REQUEST2", + [VSOCK_PACKET_TYPE_NEGOTIATE2] = "NEGOTIATE2", }; written = snprintf(cur, left, "PKT: %u:%u -> %u:%u", @@ -138,6 +140,14 @@ VSockVmciLogPkt(char const *function, // IN break; + case VSOCK_PACKET_TYPE_REQUEST2: + case VSOCK_PACKET_TYPE_NEGOTIATE2: + written = snprintf(cur, left, ", %s, size = %"FMT64"u, " + "proto = %u", + typeStrings[pkt->type], pkt->u.size, + pkt->proto); + break; + default: written = snprintf(cur, left, ", unrecognized type"); } diff --git a/open-vm-tools/modules/linux/vsock/linux/vsockPacket.h b/open-vm-tools/modules/linux/vsock/linux/vsockPacket.h index 2aa7f8be8..3e6f23da9 100644 --- a/open-vm-tools/modules/linux/vsock/linux/vsockPacket.h +++ b/open-vm-tools/modules/linux/vsock/linux/vsockPacket.h @@ -39,17 +39,26 @@ /* The resource ID on which control packets are sent. */ #define VSOCK_PACKET_RID 1 -/* Assert that the given packet is valid. */ -#define VSOCK_PACKET_ASSERT(_p) \ - ASSERT((_p)); \ - ASSERT((_p)->type < VSOCK_PACKET_TYPE_MAX); \ - ASSERT(0 == (_p)->_reserved1); \ - ASSERT(0 == (_p)->_reserved2) - +/* + * Assert that the given packet is valid. + * We check that the two original reserved fields equal zero because the + * version of the common code that shipped with ESX 4.0 and WS 6.5 did so and + * will return a RST packet if they aren't set that way. For newer packet + * types added after that release we don't do this. + */ +#define VSOCK_PACKET_ASSERT(_p) \ + do { \ + ASSERT((_p)); \ + ASSERT((_p)->type < VSOCK_PACKET_TYPE_MAX); \ + if ((_p)->type < VSOCK_PACKET_TYPE_REQUEST2) { \ + ASSERT(0 == (_p)->proto); \ + ASSERT(0 == (_p)->_reserved2); \ + } \ + } while(0) typedef enum VSockPacketType { VSOCK_PACKET_TYPE_INVALID = 0, // Invalid type. - VSOCK_PACKET_TYPE_REQUEST, // Connection request. + VSOCK_PACKET_TYPE_REQUEST, // Connection request (WR/WW/READ/WRITE) VSOCK_PACKET_TYPE_NEGOTIATE, // Connection negotiate. VSOCK_PACKET_TYPE_OFFER, // Connection offer queue pair. VSOCK_PACKET_TYPE_ATTACH, // Connection attach. @@ -59,9 +68,17 @@ typedef enum VSockPacketType { VSOCK_PACKET_TYPE_SHUTDOWN, // Shutdown the connection. VSOCK_PACKET_TYPE_WAITING_WRITE, // Notify peer we are waiting to write. VSOCK_PACKET_TYPE_WAITING_READ, // Notify peer we are waiting to read. + VSOCK_PACKET_TYPE_REQUEST2, // Connection request (new proto flags) + VSOCK_PACKET_TYPE_NEGOTIATE2, // Connection request (new proto flags) VSOCK_PACKET_TYPE_MAX // Last message. } VSockPacketType; +typedef uint16 VSockProtoVersion; +#define VSOCK_PROTO_INVALID 0 // Invalid protocol version. +#define VSOCK_PROTO_PKT_ON_NOTIFY (1 << 0) // Queuepair inspection proto. + +#define VSOCK_PROTO_ALL_SUPPORTED (VSOCK_PROTO_PKT_ON_NOTIFY) + typedef struct VSockWaitingInfo { uint64 generation; // Generation of the queue. uint64 offset; // Offset within the queue. @@ -78,7 +95,8 @@ typedef struct VSockPacket { VMCIDatagram dg; // Datagram header. uint8 version; // Version. uint8 type; // Type of message. - uint16 _reserved1; // Reserved. + VSockProtoVersion proto; // Supported proto versions in CONNECT2 and + // NEGOTIATE2. 0 otherwise. uint32 srcPort; // Source port. uint32 dstPort; // Destination port. uint32 _reserved2; // Reserved. @@ -121,6 +139,7 @@ VSockPacket_Init(VSockPacket *pkt, // OUT uint64 size, // IN uint64 mode, // IN VSockWaitingInfo *wait, // IN + VSockProtoVersion proto, // IN VMCIHandle handle) // IN { ASSERT(pkt); @@ -134,7 +153,7 @@ VSockPacket_Init(VSockPacket *pkt, // OUT pkt->type = type; pkt->srcPort = src->svm_port; pkt->dstPort = dst->svm_port; - VSockOS_ClearMemory(&pkt->_reserved1, sizeof pkt->_reserved1); + VSockOS_ClearMemory(&pkt->proto, sizeof pkt->proto); VSockOS_ClearMemory(&pkt->_reserved2, sizeof pkt->_reserved2); switch (pkt->type) { @@ -167,6 +186,12 @@ VSockPacket_Init(VSockPacket *pkt, // OUT ASSERT(wait); VSockOS_Memcpy(&pkt->u.wait, wait, sizeof pkt->u.wait); break; + + case VSOCK_PACKET_TYPE_REQUEST2: + case VSOCK_PACKET_TYPE_NEGOTIATE2: + pkt->u.size = size; + pkt->proto = proto; + break; } VSOCK_PACKET_ASSERT(pkt); @@ -216,8 +241,11 @@ VSockPacket_Validate(VSockPacket *pkt) goto exit; } - if (0 != pkt->_reserved1 || 0 != pkt->_reserved2) { - goto exit; + /* See the comment above VSOCK_PACKET_ASSERT. */ + if (pkt->type < VSOCK_PACKET_TYPE_REQUEST2) { + if (0 != pkt->proto || 0 != pkt->_reserved2) { + goto exit; + } } switch (pkt->type) { @@ -251,7 +279,7 @@ VSockPacket_Validate(VSockPacket *pkt) } err = 0; - + exit: return sockerr2err(err); } diff --git a/open-vm-tools/modules/shared/vmxnet/vmnet_def.h b/open-vm-tools/modules/shared/vmxnet/vmnet_def.h index d6a042c67..07fbbb6f6 100644 --- a/open-vm-tools/modules/shared/vmxnet/vmnet_def.h +++ b/open-vm-tools/modules/shared/vmxnet/vmnet_def.h @@ -75,4 +75,5 @@ #define VMNET_CAP_IP6_CSUM 0x80000 /* Can do IPv6 csum offload. */ #define VMNET_CAP_TSO6 0x100000 /* Can do TSO segmentation offload for IPv6 pkts. */ #define VMNET_CAP_TSO256k 0x200000 /* Can do TSO segmentation offload for pkts up to 256kB. */ +#define VMNET_CAP_UPT 0x400000 /* Support UPT */ #endif // _VMNET_DEF_H_ diff --git a/open-vm-tools/modules/shared/vmxnet/vmxnet3_defs.h b/open-vm-tools/modules/shared/vmxnet/vmxnet3_defs.h index 7ff08739f..9a6334c59 100644 --- a/open-vm-tools/modules/shared/vmxnet/vmxnet3_defs.h +++ b/open-vm-tools/modules/shared/vmxnet/vmxnet3_defs.h @@ -151,7 +151,7 @@ Vmxnet3_TxDesc; typedef #include "vmware_pack_begin.h" -struct vmxnet3_TxDataDesc { +struct Vmxnet3_TxDataDesc { uint8 data[VMXNET3_HDR_COPY_SIZE]; } #include "vmware_pack_end.h" @@ -371,7 +371,7 @@ Vmxnet3_MiscConf; typedef #include "vmware_pack_begin.h" -struct vmxnet3_TxQueueConf { +struct Vmxnet3_TxQueueConf { uint64 txRingBasePA; uint64 dataRingBasePA; uint64 compRingBasePA; diff --git a/open-vm-tools/modules/solaris/vmmemctl/os.c b/open-vm-tools/modules/solaris/vmmemctl/os.c index ecb16b19a..f3badc842 100644 --- a/open-vm-tools/modules/solaris/vmmemctl/os.c +++ b/open-vm-tools/modules/solaris/vmmemctl/os.c @@ -14,10 +14,10 @@ * *********************************************************/ -/* +/* * os.c -- * - * Wrappers for Solaris system functions required by "vmmemctl". + * Wrappers for Solaris system functions required by "vmmemctl". */ /* @@ -41,6 +41,7 @@ #include #include "os.h" +#include "vm_assert.h" #include "balloon_def.h" #include "vmballoon_kstats.h" #include "vmmemctl.h" @@ -73,7 +74,7 @@ typedef struct { kcondvar_t cv; /* registered state */ - os_timer_handler handler; + OSTimerHandler *handler; void *data; int period; } os_timer; @@ -104,33 +105,127 @@ typedef struct { static os_state global_state; static dev_info_t *vmmemctl_dip; /* only one instance */ + /* - * Simple Wrappers + *----------------------------------------------------------------------------- + * + * OS_Malloc -- + * + * Allocates kernel memory. + * + * Results: + * On success: Pointer to allocated memory + * On failure: NULL + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- */ -void *os_kmalloc_nosleep(unsigned int size) +void * +OS_Malloc(size_t size) // IN { return (kmem_alloc(size, KM_NOSLEEP)); } -void os_kfree(void *obj, unsigned int size) + +/* + *----------------------------------------------------------------------------- + * + * OS_Free -- + * + * Free allocated kernel memory. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +OS_Free(void *ptr, // IN + size_t size) // IN { - kmem_free(obj, size); + kmem_free(ptr, size); } -void os_bzero(void *b, unsigned int len) + +/* + *----------------------------------------------------------------------------- + * + * OS_MemZero -- + * + * Fill a memory location with 0s. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +OS_MemZero(void *ptr, // OUT + size_t size) // IN { - bzero(b, len); + bzero(ptr, size); } -void os_memcpy(void *dest, const void *src, unsigned int size) + +/* + *----------------------------------------------------------------------------- + * + * OS_MemCopy -- + * + * Copy a memory portion into another location. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +OS_MemCopy(void *dest, // OUT + const void *src, // IN + size_t size) // IN { bcopy(src, dest, size); } -int os_sprintf(char *str, const char *format, ...) + +/* + *----------------------------------------------------------------------------- + * + * OS_Snprintf -- + * + * Print a string into a bounded memory location. + * + * Results: + * Number of character printed including trailing \0. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +int +OS_Snprintf(char *buf, // OUT + size_t size, // IN + const char *format, // IN + ...) // IN { - ASSERT(0); + NOT_REACHED(); /* * XXX disabled because the varargs header file doesn't seem to * work in the current (gcc 2.95.3) cross-compiler environment. @@ -143,7 +238,8 @@ int os_sprintf(char *str, const char *format, ...) * System-Dependent Operations */ -char *os_identity(void) +const char * +OS_Identity(void) { return "solaris"; } @@ -153,12 +249,14 @@ char *os_identity(void) * * Currently we just return the total memory pages. */ -unsigned int os_predict_max_balloon_pages(void) +unsigned int +OS_PredictMaxReservedPages(void) { return(maxmem); } -unsigned long os_addr_to_ppn(unsigned long addr) +unsigned long +OS_AddrToPPN(unsigned long addr) { return (ulong_t)page_pptonum(((os_page *)addr)->pp); } @@ -184,7 +282,8 @@ unsigned long os_addr_to_ppn(unsigned long addr) * interface for allocating physical pages that may allow us to * eliminate some of this. */ -unsigned long os_alloc_reserved_page(int can_sleep) +unsigned long +OS_AllocReservedPage(int canSleep) { os_state *state = &global_state; page_t *pp; @@ -198,12 +297,12 @@ unsigned long os_alloc_reserved_page(int can_sleep) /* * Reserve space for the page. */ - flags = can_sleep ? KM_SLEEP : KM_NOSLEEP; + flags = canSleep ? KM_SLEEP : KM_NOSLEEP; if (!page_resv(1, flags)) return 0; /* no space! */ /* - * Allocating space for os_page early simplifies error handling. + * Allocating space for os_page early simplifies error handling. */ if ((page = kmem_alloc(sizeof (os_page), flags)) == NULL) { page_unresv(1); @@ -219,7 +318,7 @@ unsigned long os_alloc_reserved_page(int can_sleep) * Allocate the page itself. Note that this can fail. */ kseg.s_as = &kas; - flags = can_sleep ? PG_EXCL | PG_WAIT : PG_EXCL; + flags = canSleep ? PG_EXCL | PG_WAIT : PG_EXCL; pp = page_create_va(vp, off, PAGESIZE, flags, &kseg, (caddr_t)(ulong_t)off); if (pp != NULL) { @@ -245,7 +344,8 @@ unsigned long os_alloc_reserved_page(int can_sleep) return (unsigned long)page; } -void os_free_reserved_page(unsigned long addr) +void +OS_FreeReservedPage(unsigned long addr) { os_state *state = &global_state; os_page *page = (os_page *)addr; @@ -296,13 +396,16 @@ static int os_worker(void) /* * Initialize timer data. */ -void os_timer_init(os_timer_handler handler, void *data, int period) +void +OS_TimerInit(OSTimerHandler *handler, // IN + void *clientData, // IN + int period) // IN { os_timer *t = &global_state.timer; t->id = 0; t->handler = handler; - t->data = data; + t->data = clientData; t->period = period; t->stop = 0; @@ -310,14 +413,16 @@ void os_timer_init(os_timer_handler handler, void *data, int period) cv_init(&t->cv, NULL, CV_DRIVER, NULL); } -void os_timer_start(void) +void +OS_TimerStart(void) { os_timer *t = &global_state.timer; t->stop = 0; } -void os_timer_stop(void) +void +OS_TimerStop(void) { os_timer *t = &global_state.timer; @@ -340,19 +445,38 @@ static void os_timer_cleanup(void) cv_destroy(&timer->cv); } -unsigned int os_timer_hz(void) +unsigned int +OS_TimerHz(void) { return drv_usectohz(ONE_SECOND_IN_MICROSECONDS); } -void os_yield(void) + +/* + *----------------------------------------------------------------------------- + * + * OS_Yield -- + * + * Yield the CPU, if needed. + * + * Results: + * None + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +void +OS_Yield(void) { /* Do nothing. */ } -void os_init(const char *name, +void OS_Init(const char *name, const char *name_verbose, - os_status_handler handler) + OSStatusHandler *handler) { os_state *state = &global_state; static int initialized = 0; @@ -381,7 +505,7 @@ void os_init(const char *name, cmn_err(CE_CONT, "!%s initialized\n", name_verbose); } -void os_cleanup(void) +void OS_Cleanup(void) { os_state *state = &global_state; diff --git a/open-vm-tools/modules/solaris/vmmemctl/os.h b/open-vm-tools/modules/solaris/vmmemctl/os.h index 7061eabf1..39d5d2a25 100644 --- a/open-vm-tools/modules/solaris/vmmemctl/os.h +++ b/open-vm-tools/modules/solaris/vmmemctl/os.h @@ -14,62 +14,49 @@ * *********************************************************/ -/* +/* * os.h -- * - * Definitions for OS-specific wrapper functions required - * by "vmmemctl". This allows customers to build their own - * vmmemctl driver for custom versioned kernels without the - * need for source code. + * Definitions for OS-specific wrapper functions required by "vmmemctl". */ #ifndef OS_H #define OS_H -/* - * Needs fixing for 64bit OSes - */ -#ifndef __x86_64__ -#define CDECL __attribute__((cdecl, regparm(0))) -#else -#define CDECL -#endif - /* * Types */ -typedef void CDECL (*os_timer_handler)(void *); -typedef int CDECL (*os_status_handler)(char *); +typedef void OSTimerHandler(void *clientData); +typedef int OSStatusHandler(char *buf, size_t size); /* * Operations */ -extern void CDECL *os_kmalloc_nosleep(unsigned int size); -extern void CDECL os_kfree(void *obj, unsigned int size); -extern void CDECL os_yield(void); -extern void CDECL os_bzero(void *s, unsigned int n); -extern void CDECL os_memcpy(void *dest, const void *src, unsigned int size); -extern int CDECL os_sprintf(char *str, const char *format, ...); - -extern unsigned long CDECL os_addr_to_ppn(unsigned long addr); -extern unsigned long CDECL os_alloc_reserved_page(int can_sleep); -extern void CDECL os_free_reserved_page(unsigned long page); +extern void OS_Init(const char *name, + const char *nameVerbose, + OSStatusHandler *handler); +extern void OS_Cleanup(void); +extern const char *OS_Identity(void); -extern void CDECL os_timer_init(os_timer_handler handler, void *data, int period); -extern void CDECL os_timer_start(void); -extern void CDECL os_timer_stop(void); +extern void OS_MemZero(void *ptr, size_t size); +extern void OS_MemCopy(void *dest, const void *src, size_t size); +extern int OS_Snprintf(char *buf, size_t size, const char *format, ...); -extern void CDECL os_init(const char *name, - const char *name_verbose, - os_status_handler handler); -extern void CDECL os_cleanup(void); +extern void *OS_Malloc(size_t size); +extern void OS_Free(void *ptr, size_t size); -extern char CDECL *os_identity(void); +extern void OS_Yield(void); -extern unsigned int CDECL os_predict_max_balloon_pages(void); +extern unsigned int OS_TimerHz(void); +extern void OS_TimerInit(OSTimerHandler *handler, void *clientData, int period); +extern void OS_TimerStart(void); +extern void OS_TimerStop(void); -extern unsigned int CDECL os_timer_hz(void); +extern unsigned int OS_PredictMaxReservedPages(void); +extern unsigned long OS_AddrToPPN(unsigned long addr); +extern unsigned long OS_AllocReservedPage(int canSleep); +extern void OS_FreeReservedPage(unsigned long page); #endif /* OS_H */ diff --git a/open-vm-tools/modules/solaris/vmmemctl/vmballoon.c b/open-vm-tools/modules/solaris/vmmemctl/vmballoon.c index 8e68226a1..f2f055878 100644 --- a/open-vm-tools/modules/solaris/vmmemctl/vmballoon.c +++ b/open-vm-tools/modules/solaris/vmmemctl/vmballoon.c @@ -14,18 +14,18 @@ * *********************************************************/ -/* +/* * vmballoon.c -- * - * VMware server physical memory management driver for Unix-ish - * (Linux, FreeBSD, Solaris) guests. The driver acts like a - * "balloon" that can be inflated to reclaim physical pages by - * reserving them in the guest and invalidating them in the - * monitor, freeing up the underlying machine pages so they can - * be allocated to other guests. The balloon can also be - * deflated to allow the guest to use more physical memory. - * Higher level policies can control the sizes of balloons in VMs - * in order to manage physical memory resources. + * VMware physical memory management driver for Unix-ish + * (Linux, FreeBSD, Solaris, Mac OS) guests. The driver acts like + * a "balloon" that can be inflated to reclaim physical pages by + * reserving them in the guest and invalidating them in the + * monitor, freeing up the underlying machine pages so they can + * be allocated to other guests. The balloon can also be + * deflated to allow the guest to use more physical memory. + * Higher level policies can control the sizes of balloons in VMs + * in order to manage physical memory resources. */ #ifdef __cplusplus @@ -36,12 +36,12 @@ extern "C" { * Compile-Time Options */ -#define BALLOON_RATE_ADAPT (1) +#define BALLOON_RATE_ADAPT (1) -#define BALLOON_DEBUG (1) -#define BALLOON_DEBUG_VERBOSE (0) +#define BALLOON_DEBUG (1) +#define BALLOON_DEBUG_VERBOSE (0) -#define BALLOON_STATS +#define BALLOON_STATS #define BALLOON_STATS_PROCFS /* @@ -63,38 +63,38 @@ extern "C" { #define NULL 0 #endif -#define BALLOON_NAME "vmmemctl" -#define BALLOON_NAME_VERBOSE "VMware memory control driver" +#define BALLOON_NAME "vmmemctl" +#define BALLOON_NAME_VERBOSE "VMware memory control driver" -#define BALLOON_PROTOCOL_VERSION (2) +#define BALLOON_PROTOCOL_VERSION (2) -#define BALLOON_CHUNK_PAGES (1000) +#define BALLOON_CHUNK_PAGES (1000) -#define BALLOON_NOSLEEP_ALLOC_MAX (16384) +#define BALLOON_NOSLEEP_ALLOC_MAX (16384) -#define BALLOON_RATE_ALLOC_MIN (512) -#define BALLOON_RATE_ALLOC_MAX (2048) -#define BALLOON_RATE_ALLOC_INC (16) +#define BALLOON_RATE_ALLOC_MIN (512) +#define BALLOON_RATE_ALLOC_MAX (2048) +#define BALLOON_RATE_ALLOC_INC (16) -#define BALLOON_RATE_FREE_MIN (512) -#define BALLOON_RATE_FREE_MAX (16384) -#define BALLOON_RATE_FREE_INC (16) +#define BALLOON_RATE_FREE_MIN (512) +#define BALLOON_RATE_FREE_MAX (16384) +#define BALLOON_RATE_FREE_INC (16) -#define BALLOON_ERROR_PAGES (16) +#define BALLOON_ERROR_PAGES (16) -/* +/* * When guest is under memory pressure, use a reduced page allocation * rate for next several cycles. */ -#define SLOW_PAGE_ALLOCATION_CYCLES (4) +#define SLOW_PAGE_ALLOCATION_CYCLES (4) -/* +/* * Move it to bora/public/balloon_def.h later, if needed. Note that * BALLOON_PAGE_ALLOC_FAILURE is an internal error code used for * distinguishing page allocation failures from monitor-backdoor errors. * We use value 1000 because all monitor-backdoor error codes are < 1000. */ -#define BALLOON_PAGE_ALLOC_FAILURE (1000) +#define BALLOON_PAGE_ALLOC_FAILURE (1000) // Maximum number of page allocations without yielding processor #define BALLOON_ALLOC_YIELD_THRESHOLD (1024) @@ -154,7 +154,7 @@ static Balloon globalBalloon; static int BalloonGuestType(void); static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep); -static void BalloonPrimFreePage(unsigned long page); +static void BalloonPrimFreePage(unsigned long page); static int Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType); static int Balloon_FreePage(Balloon *b, int monitorUnlock); @@ -163,7 +163,7 @@ static void Balloon_Reset(Balloon *b); static void Balloon_StartTimer(Balloon *b); static void Balloon_StopTimer(Balloon *b); -static void CDECL Balloon_BH(void *data); +static void BalloonTimerHandler(void *clientData); static int Balloon_MonitorStart(Balloon *b); static int Balloon_MonitorGuestType(Balloon *b); @@ -175,51 +175,43 @@ static int Balloon_MonitorUnlockPage(Balloon *b, unsigned long addr); * Macros */ -#ifndef MIN -#define MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif -#ifndef MAX -#define MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif - -#ifdef BALLOON_STATS -#define STATS_INC(stat) (stat)++ +#ifdef BALLOON_STATS +#define STATS_INC(stat) (stat)++ #else -#define STATS_INC(stat) +#define STATS_INC(stat) #endif /* * Macros to generate operations for simple lists of OBJ. * OBJ must contain next and prev fields. - * */ -#define GENERATE_LIST_INSERT(OBJ) \ -static void OBJ ## _Insert(OBJ **head, OBJ *obj) \ -{ \ - OBJ *h = *head; \ - \ - /* add element to head of list */ \ - obj->next = h; \ - if (h != NULL) { \ - h->prev = obj; \ - } \ - *head = obj; \ - obj->prev = NULL; \ +#define GENERATE_LIST_INSERT(OBJ) \ +static void OBJ ## _Insert(OBJ **head, OBJ *obj) \ +{ \ + OBJ *h = *head; \ + \ + /* add element to head of list */ \ + obj->next = h; \ + if (h != NULL) { \ + h->prev = obj; \ + } \ + *head = obj; \ + obj->prev = NULL; \ } -#define GENERATE_LIST_REMOVE(OBJ) \ -static void OBJ ## _Remove(OBJ **head, OBJ *obj) \ -{ \ - /* splice element out of list */ \ - if (obj->prev != NULL) { \ - obj->prev->next = obj->next; \ - } else { \ - *head = obj->next; \ - } \ - if (obj->next != NULL) { \ - obj->next->prev = obj->prev; \ - } \ +#define GENERATE_LIST_REMOVE(OBJ) \ +static void OBJ ## _Remove(OBJ **head, OBJ *obj) \ +{ \ + /* splice element out of list */ \ + if (obj->prev != NULL) { \ + obj->prev->next = obj->next; \ + } else { \ + *head = obj->next; \ + } \ + if (obj->next != NULL) { \ + obj->next->prev = obj->prev; \ + } \ } /* @@ -233,25 +225,28 @@ GENERATE_LIST_REMOVE(BalloonChunk); * Procfs Operations */ + /* *---------------------------------------------------------------------- * * BalloonProcRead -- * * Ballon driver status reporting routine. Note that this is only - * used for Linux. + * used for Linux. * * Results: * Writes ASCII status information into "buf". - * Returns number of bytes written. + * Returns number of bytes written. * * Side effects: * None. * *---------------------------------------------------------------------- */ -static int CDECL -BalloonProcRead(char *buf) + +static int +BalloonProcRead(char *buf, // OUT + size_t size) // IN { int len = 0; BalloonStats stats; @@ -259,14 +254,14 @@ BalloonProcRead(char *buf) BalloonGetStats(&stats); /* format size info */ - len += os_sprintf(buf + len, + len += OS_Snprintf(buf + len, size - len, "target: %8d pages\n" "current: %8d pages\n", stats.nPagesTarget, stats.nPages); /* format rate info */ - len += os_sprintf(buf + len, + len += OS_Snprintf(buf + len, size - len, "rateNoSleepAlloc: %8d pages/sec\n" "rateSleepAlloc: %8d pages/sec\n" "rateFree: %8d pages/sec\n", @@ -274,8 +269,8 @@ BalloonProcRead(char *buf) stats.rateAlloc, stats.rateFree); -#ifdef BALLOON_STATS_PROCFS - len += os_sprintf(buf + len, +#ifdef BALLOON_STATS_PROCFS + len += OS_Snprintf(buf + len, size - len, "\n" "timer: %8u\n" "start: %8u (%4u failed)\n" @@ -303,7 +298,7 @@ BalloonProcRead(char *buf) stats.primErrorPageFree); #endif - return(len); + return len; } /* @@ -316,7 +311,7 @@ BalloonProcRead(char *buf) * AddrToPPN -- * * Return the physical page number corresponding to the specified - * Linux kernel-mapped address. + * kernel-mapped address. * * Results: * Returns PPN for "addr". @@ -329,7 +324,7 @@ BalloonProcRead(char *buf) static inline unsigned long AddrToPPN(unsigned long addr) { - return(os_addr_to_ppn(addr)); + return OS_AddrToPPN(addr); } /* @@ -339,12 +334,12 @@ AddrToPPN(unsigned long addr) * * Attempts to allocate and reserve a physical page. * - * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP: - * The allocation can wait (sleep) for page writeout (swap) - * by the guest. - * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP: - * If allocation of a page requires disk writeout, then - * just fail. DON'T sleep. + * If canSleep == 1, i.e., BALLOON_PAGE_ALLOC_CANSLEEP: + * The allocation can wait (sleep) for page writeout (swap) + * by the guest. + * otherwise canSleep == 0, i.e., BALLOON_PAGE_ALLOC_NOSLEEP: + * If allocation of a page requires disk writeout, then + * just fail. DON'T sleep. * * Results: * Returns the physical address of the allocated page, or 0 if error. @@ -357,7 +352,7 @@ AddrToPPN(unsigned long addr) static unsigned long BalloonPrimAllocPage(BalloonPageAllocType canSleep) { - return(os_alloc_reserved_page(canSleep)); + return OS_AllocReservedPage(canSleep); } /* @@ -378,7 +373,7 @@ BalloonPrimAllocPage(BalloonPageAllocType canSleep) static void BalloonPrimFreePage(unsigned long page) { - return(os_free_reserved_page(page)); + return OS_FreeReservedPage(page); } /* @@ -387,7 +382,7 @@ BalloonPrimFreePage(unsigned long page) * BalloonGuestType -- * * Return balloon guest OS identifier obtained by parsing - * system-dependent identity string. + * system-dependent identity string. * * Results: * Returns one of BALLOON_GUEST_{LINUX,BSD,SOLARIS,UNKNOWN}. @@ -400,11 +395,11 @@ BalloonPrimFreePage(unsigned long page) static int BalloonGuestType(void) { - char *identity; + const char *identity; /* obtain OS identify string */ - identity = os_identity(); - + identity = OS_Identity(); + /* unknown if not specified */ if (identity == NULL) { return(BALLOON_GUEST_UNKNOWN); @@ -414,19 +409,19 @@ BalloonGuestType(void) switch (identity[0]) { case 'l': case 'L': - return(BALLOON_GUEST_LINUX); + return BALLOON_GUEST_LINUX; case 'b': case 'B': - return(BALLOON_GUEST_BSD); + return BALLOON_GUEST_BSD; case 's': case 'S': - return(BALLOON_GUEST_SOLARIS); + return BALLOON_GUEST_SOLARIS; default: break; } /* unknown */ - return(BALLOON_GUEST_UNKNOWN); + return BALLOON_GUEST_UNKNOWN; } /* @@ -441,7 +436,7 @@ void BalloonGetStats(BalloonStats *stats) /* * Copy statistics out of global structure. */ - os_memcpy(stats, &b->stats, sizeof (BalloonStats)); + OS_MemCopy(stats, &b->stats, sizeof (BalloonStats)); /* * Fill in additional information about size and rates, which is @@ -463,37 +458,41 @@ void BalloonGetStats(BalloonStats *stats) * BalloonChunk_Create -- * * Creates a new BalloonChunk object capable of tracking - * BALLOON_CHUNK_PAGES PPNs. + * BALLOON_CHUNK_PAGES PPNs. * - * We do not bother to define two versions (NOSLEEP and CANSLEEP) - * of os_kmalloc because Chunk_Create does not require a new page - * often. + * We do not bother to define two versions (NOSLEEP and CANSLEEP) + * of OS_Malloc because Chunk_Create does not require a new page + * often. * * Results: - * Returns initialized BalloonChunk, or NULL if error. + * On success: initialized BalloonChunk + * On failure: NULL * * Side effects: - * None. + * None * *---------------------------------------------------------------------- */ + static BalloonChunk * BalloonChunk_Create(void) { BalloonChunk *chunk; /* allocate memory, fail if unable */ - if ((chunk = (BalloonChunk *) os_kmalloc_nosleep(sizeof(BalloonChunk))) == NULL) { - return(NULL); + chunk = OS_Malloc(sizeof *chunk); + if (chunk == NULL) { + return NULL; } /* initialize */ - os_bzero(chunk, sizeof(BalloonChunk)); + OS_MemZero(chunk, sizeof *chunk); /* everything OK */ - return(chunk); + return chunk; } + /* *---------------------------------------------------------------------- * @@ -513,7 +512,7 @@ static void BalloonChunk_Destroy(BalloonChunk *chunk) { /* reclaim storage */ - os_kfree(chunk, sizeof (BalloonChunk)); + OS_Free(chunk, sizeof *chunk); } /* @@ -540,7 +539,7 @@ static int Balloon_Init(Balloon *b) { /* clear state */ - os_bzero(b, sizeof(Balloon)); + OS_MemZero(b, sizeof *b); /* initialize rates */ b->rateAlloc = BALLOON_RATE_ALLOC_MAX; @@ -578,7 +577,7 @@ Balloon_Deallocate(Balloon *b) (void) Balloon_FreePage(b, FALSE); if (++cnt >= b->rateFree) { cnt = 0; - os_yield(); + OS_Yield(); } } } @@ -589,7 +588,7 @@ Balloon_Deallocate(Balloon *b) * Balloon_Reset -- * * Resets balloon "b" to empty state. Frees all allocated pages - * and attempts to reset contact with the monitor. + * and attempts to reset contact with the monitor. * * Results: * None. @@ -621,12 +620,12 @@ Balloon_Reset(Balloon *b) /* *---------------------------------------------------------------------- * - * Balloon_BH -- + * BalloonTimerHandler -- * * Balloon bottom half handler. Contacts monitor via backdoor - * to obtain balloon size target, and starts adjusting balloon - * size to achieve target by allocating or deallocating pages. - * Resets balloon if requested by the monitor. + * to obtain balloon size target, and starts adjusting balloon + * size to achieve target by allocating or deallocating pages. + * Resets balloon if requested by the monitor. * * Results: * None. @@ -636,10 +635,10 @@ Balloon_Reset(Balloon *b) * *---------------------------------------------------------------------- */ -static void CDECL -Balloon_BH(void *data) +static void +BalloonTimerHandler(void *clientData) { - Balloon *b = (Balloon *) data; + Balloon *b = (Balloon *) clientData; uint32 target; int status; @@ -677,14 +676,14 @@ Balloon_BH(void *data) * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ static void Balloon_StartTimer(Balloon *b) { - os_timer_start(); + OS_TimerStart(); } /* @@ -698,14 +697,14 @@ Balloon_StartTimer(Balloon *b) * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ static void Balloon_StopTimer(Balloon *b) { - os_timer_stop(); + OS_TimerStop(); } @@ -715,14 +714,14 @@ Balloon_StopTimer(Balloon *b) * Balloon_ErrorPagesAlloc -- * * Attempt to add "page" to list of non-balloonable pages - * associated with "b". + * associated with "b". * * Results: - * Returns BALLOON_SUCCESS iff successful, or BALLOON_FAILURE - * if non-balloonable page list is already full. + * On success: BALLOON_SUCCESS + * On failure: BALLOON_FAILURE (non-balloonable page list is already full) * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -747,13 +746,13 @@ Balloon_ErrorPagesAlloc(Balloon *b, unsigned long page) * Balloon_ErrorPagesFree -- * * Deallocates all pages on the list of non-balloonable pages - * associated with "b". + * associated with "b". * * Results: - * None. + * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -764,7 +763,7 @@ Balloon_ErrorPagesFree(Balloon *b) /* free all non-balloonable "error" pages */ for (i = 0; i < b->errors.nextPage; i++) { - BalloonPrimFreePage(b->errors.page[i]); + BalloonPrimFreePage(b->errors.page[i]); b->errors.page[i] = 0; STATS_INC(b->stats.primErrorPageFree); } @@ -777,13 +776,13 @@ Balloon_ErrorPagesFree(Balloon *b) * Balloon_AllocPage -- * * Attempts to allocate a physical page, inflating balloon "b". - * Informs monitor of PPN for allocated page via backdoor. + * Informs monitor of PPN for allocated page via backdoor. * * Results: * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -852,14 +851,14 @@ Balloon_AllocPage(Balloon *b, BalloonPageAllocType allocType) * Balloon_FreePage -- * * Attempts to deallocate a physical page, deflating balloon "b". - * Informs monitor of PPN for deallocated page via backdoor if - * "monitorUnlock" is specified. + * Informs monitor of PPN for deallocated page via backdoor if + * "monitorUnlock" is specified. * * Results: * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -927,15 +926,15 @@ Balloon_FreePage(Balloon *b, int monitorUnlock) * * BalloonDecreaseRateAlloc -- * - * Wrapper to quickly reduce the page allocation rate. This function - * is called only when a CANSLEEP allocation fails. This implies severe - * memory pressure inside the guest, so quickly decrease the rateAlloc. + * Wrapper to quickly reduce the page allocation rate. This function + * is called only when a CANSLEEP allocation fails. This implies severe + * memory pressure inside the guest, so quickly decrease the rateAlloc. * * Results: * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -952,27 +951,27 @@ BalloonDecreaseRateAlloc(Balloon *b) * * BalloonIncreaseRateAlloc -- * - * Wrapper to increase the page allocation rate. + * Wrapper to increase the page allocation rate. * - * This function is called when the balloon target is met or - * b->rateAlloc (or more) pages have been successfully allocated. - * This implies that the guest may not be under high memory - * pressure. So let us increase the rateAlloc. + * This function is called when the balloon target is met or + * b->rateAlloc (or more) pages have been successfully allocated. + * This implies that the guest may not be under high memory + * pressure. So let us increase the rateAlloc. * - * If meeting balloon target requires less than b->rateAlloc - * pages, then we do not change the page allocation rate. + * If meeting balloon target requires less than b->rateAlloc + * pages, then we do not change the page allocation rate. * - * If the number of pages successfully allocated (nAlloc) is far - * higher than b->rateAlloc, then it implies that NOSLEEP - * allocations are highly successful. Therefore, we predict that - * the guest is under no memory pressure, and so increase - * b->rateAlloc quickly. + * If the number of pages successfully allocated (nAlloc) is far + * higher than b->rateAlloc, then it implies that NOSLEEP + * allocations are highly successful. Therefore, we predict that + * the guest is under no memory pressure, and so increase + * b->rateAlloc quickly. * * Results: * None. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -981,7 +980,7 @@ BalloonIncreaseRateAlloc(Balloon *b, uint32 nAlloc) { if (BALLOON_RATE_ADAPT) { if (nAlloc >= b->rateAlloc) { - uint32 mult = nAlloc / b->rateAlloc; + uint32 mult = nAlloc / b->rateAlloc; b->rateAlloc = MIN(b->rateAlloc + mult * BALLOON_RATE_ALLOC_INC, BALLOON_RATE_ALLOC_MAX); } @@ -999,7 +998,7 @@ BalloonIncreaseRateAlloc(Balloon *b, uint32 nAlloc) * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1009,7 +1008,7 @@ BalloonInflate(Balloon *b, uint32 target) int status, allocations = 0; uint32 i, nAllocNoSleep, nAllocCanSleep; - /* + /* * First try NOSLEEP page allocations to inflate balloon. * * If we do not throttle nosleep allocations, we can drain all @@ -1017,10 +1016,10 @@ BalloonInflate(Balloon *b, uint32 target) * As a side-effect, draining free pages helps to inform (force) * the guest to start swapping if balloon target is not met yet, * which is a desired behavior. However, balloon driver can consume - * all available CPU cycles if too many pages are allocated in a - * second. Therefore, we throttle nosleep allocations even when - * the guest is not under memory pressure. OTOH, if we have already - * predicted that the guest is under memory pressure, then we + * all available CPU cycles if too many pages are allocated in a + * second. Therefore, we throttle nosleep allocations even when + * the guest is not under memory pressure. OTOH, if we have already + * predicted that the guest is under memory pressure, then we * slowdown page allocations considerably. */ if (b->slowPageAllocationCycles > 0) { @@ -1034,16 +1033,16 @@ BalloonInflate(Balloon *b, uint32 target) status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_NOSLEEP); if (status != BALLOON_SUCCESS) { if (status != BALLOON_PAGE_ALLOC_FAILURE) { - /* + /* * Not a page allocation failure, so release non-balloonable * pages, and fail. */ Balloon_ErrorPagesFree(b); return(status); } - /* - * NOSLEEP page allocation failed, so the guest is under memory - * pressure. Let us slowdown page allocations for next few + /* + * NOSLEEP page allocation failed, so the guest is under memory + * pressure. Let us slowdown page allocations for next few * cycles so that the guest gets out of memory pressure. */ b->slowPageAllocationCycles = SLOW_PAGE_ALLOCATION_CYCLES; @@ -1051,12 +1050,12 @@ BalloonInflate(Balloon *b, uint32 target) } if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) { - os_yield(); + OS_Yield(); allocations = 0; } } - /* + /* * Check whether nosleep allocation successfully zapped nAllocNoSleep * pages. */ @@ -1066,7 +1065,7 @@ BalloonInflate(Balloon *b, uint32 target) Balloon_ErrorPagesFree(b); return(BALLOON_SUCCESS); } else { - /* + /* * NOSLEEP allocation failed, so the guest is under memory pressure. * If already b->rateAlloc pages were zapped, then succeed. Otherwise, * try CANSLEEP allocation. @@ -1082,14 +1081,14 @@ BalloonInflate(Balloon *b, uint32 target) } } - /* + /* * Use CANSLEEP page allocation to inflate balloon if below target. * * Sleep allocations are required only when nosleep allocation fails. * This implies that the guest is already under memory pressure, so * let us always throttle canSleep allocations. The total number pages - * allocated using noSleep and canSleep methods is throttled at - * b->rateAlloc per second when the guest is under memory pressure. + * allocated using noSleep and canSleep methods is throttled at + * b->rateAlloc per second when the guest is under memory pressure. */ nAllocCanSleep = target - b->nPages; nAllocCanSleep = MIN(nAllocCanSleep, b->rateAlloc - nAllocNoSleep); @@ -1099,7 +1098,7 @@ BalloonInflate(Balloon *b, uint32 target) status = Balloon_AllocPage(b, BALLOON_PAGE_ALLOC_CANSLEEP); if(status != BALLOON_SUCCESS) { if (status == BALLOON_PAGE_ALLOC_FAILURE) { - /* + /* * CANSLEEP page allocation failed, so guest is under severe * memory pressure. Quickly decrease rateAlloc. */ @@ -1111,17 +1110,17 @@ BalloonInflate(Balloon *b, uint32 target) } if (++allocations > BALLOON_ALLOC_YIELD_THRESHOLD) { - os_yield(); + OS_Yield(); allocations = 0; } } - /* + /* * Either met the balloon target or b->rateAlloc pages have been * successfully zapped. */ BalloonIncreaseRateAlloc(b, nAllocNoSleep + nAllocCanSleep); - + /* release non-balloonable pages, succeed */ Balloon_ErrorPagesFree(b); return(BALLOON_SUCCESS); @@ -1138,7 +1137,7 @@ BalloonInflate(Balloon *b, uint32 target) * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1147,7 +1146,7 @@ BalloonDeflate(Balloon *b, uint32 target) { int status, i; uint32 nFree = b->nPages - target; - + /* limit deallocation rate */ nFree = MIN(nFree, b->rateFree); @@ -1171,20 +1170,20 @@ BalloonDeflate(Balloon *b, uint32 target) /* everything OK */ return(BALLOON_SUCCESS); } - + /* *---------------------------------------------------------------------- * * Balloon_AdjustSize -- * * Attempts to allocate or deallocate physical pages in order - * to reach desired "target" size for balloon "b". + * to reach desired "target" size for balloon "b". * * Results: * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1222,10 +1221,10 @@ Balloon_AdjustSize(Balloon *b, uint32 target) * Attempts to contact monitor via backdoor to begin operation. * * Results: - * Returns BALLOON_SUCCESS if successful, otherwise error code. + * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1264,10 +1263,10 @@ Balloon_MonitorStart(Balloon *b) * Attempts to contact monitor and report guest OS identity. * * Results: - * Returns BALLOON_SUCCESS if successful, otherwise error code. + * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1309,24 +1308,24 @@ Balloon_MonitorGuestType(Balloon *b) * Balloon_MonitorGetTarget -- * * Attempts to contact monitor via backdoor to obtain desired - * balloon size. + * balloon size. * - * Predicts the maximum achievable balloon size and sends it - * to vmm => vmkernel via vEbx register. + * Predicts the maximum achievable balloon size and sends it + * to vmm => vmkernel via vEbx register. * - * os_predict_max_balloon_pages() returns either predicted max balloon - * pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario, - * vmkernel uses global config options for determining a guest's max - * balloon size. Note that older vmballoon drivers set vEbx to - * BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel - * will fallback to config-based max balloon size estimation. + * OS_PredictMaxReservedPages() returns either predicted max balloon + * pages or BALLOON_MAX_SIZE_USE_CONFIG. In the later scenario, + * vmkernel uses global config options for determining a guest's max + * balloon size. Note that older vmballoon drivers set vEbx to + * BALLOON_MAX_SIZE_USE_CONFIG, i.e., value 0 (zero). So vmkernel + * will fallback to config-based max balloon size estimation. * * Results: - * If successful, sets "target" to value obtained from monitor, + * If successful, sets "target" to value obtained from monitor, * and returns BALLOON_SUCCESS. Otherwise returns error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1338,7 +1337,7 @@ Balloon_MonitorGetTarget(Balloon *b, uint32 *target) /* prepare backdoor args */ bp.in.cx.halfs.low = BALLOON_BDOOR_CMD_TARGET; - bp.in.size = os_predict_max_balloon_pages(); + bp.in.size = OS_PredictMaxReservedPages(); /* invoke backdoor */ Backdoor_Balloon(&bp); @@ -1367,14 +1366,14 @@ Balloon_MonitorGetTarget(Balloon *b, uint32 *target) * * Balloon_MonitorLockPage -- * - * Attempts to contact monitor and add PPN containing "addr" - * to set of "balloon locked" pages. + * Attempts to contact monitor and add PPN containing "addr" + * to set of "balloon locked" pages. * * Results: - * Returns BALLOON_SUCCESS if successful, otherwise error code. + * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1426,14 +1425,14 @@ Balloon_MonitorLockPage(Balloon *b, unsigned long addr) * * Balloon_MonitorUnlockPage -- * - * Attempts to contact monitor and remove PPN containing "addr" - * from set of "balloon locked" pages. + * Attempts to contact monitor and remove PPN containing "addr" + * from set of "balloon locked" pages. * * Results: - * Returns BALLOON_SUCCESS if successful, otherwise error code. + * Returns BALLOON_SUCCESS if successful, otherwise error code. * * Side effects: - * None. + * None. * *---------------------------------------------------------------------- */ @@ -1495,18 +1494,18 @@ BalloonModuleInit(void) return(BALLOON_FAILURE); } + /* os-specific initialization */ + OS_Init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead); + /* initialize global state */ Balloon_Init(b); - /* os-specific initialization */ - os_init(BALLOON_NAME, BALLOON_NAME_VERBOSE, BalloonProcRead); - os_timer_init(Balloon_BH, (void *) b, os_timer_hz()); - /* start timer */ + OS_TimerInit(BalloonTimerHandler, b, OS_TimerHz()); Balloon_StartTimer(b); /* everything OK */ - return(BALLOON_SUCCESS); + return BALLOON_SUCCESS; } static void @@ -1526,8 +1525,8 @@ BalloonModuleCleanup(void) Balloon_Deallocate(b); /* os-specific cleanup */ - os_cleanup(); -} + OS_Cleanup(); +} int init_module(void) { diff --git a/open-vm-tools/services/plugins/guestInfo/guestInfoServer.c b/open-vm-tools/services/plugins/guestInfo/guestInfoServer.c index 4adb1f06e..c860b0fe6 100644 --- a/open-vm-tools/services/plugins/guestInfo/guestInfoServer.c +++ b/open-vm-tools/services/plugins/guestInfo/guestInfoServer.c @@ -33,6 +33,10 @@ #include #include +#ifndef WIN32 +# include +#endif + #include "vmware.h" #include "buildNumber.h" #include "conf.h" @@ -70,7 +74,7 @@ VM_EMBED_VERSION(VMTOOLSD_VERSION_STRING); typedef struct _GuestInfoCache{ char value[INFO_MAX][MAX_VALUE_LEN]; /* Stores values of all key-value pairs. */ - GuestNicList nicInfo; + NicInfoV3 *nicInfo; GuestDiskInfo diskInfo; } GuestInfoCache; @@ -89,10 +93,10 @@ static Bool vmResumed; static Bool GuestInfoUpdateVmdb(ToolsAppCtx *ctx, GuestInfoType infoType, void *info); static Bool SetGuestInfo(ToolsAppCtx *ctx, GuestInfoType key, const char *value, char delimiter); -static Bool NicInfoChanged(GuestNicList *nicInfo); +static Bool NicInfoChanged(NicInfoV3 *nicInfo); static Bool DiskInfoChanged(PGuestDiskInfo diskInfo); static void GuestInfoClearCache(void); -static int PrintNicInfo(GuestNicList *nicInfo, int (*PrintFunc)(const char *, ...)); +static GuestNicList *NicInfoV3ToV2(const NicInfoV3 *infoV3); /** @@ -302,7 +306,7 @@ GuestInfoGather(gpointer data) char osNameFull[MAX_VALUE_LEN]; char osName[MAX_VALUE_LEN]; gboolean disableQueryDiskInfo; - GuestNicList nicInfo; + NicInfoV3 *nicInfo = NULL; GuestDiskInfo diskInfo; #if defined(_WIN32) || defined(linux) GuestMemInfo vmStats = {0}; @@ -311,8 +315,6 @@ GuestInfoGather(gpointer data) g_debug("Entered guest info gather.\n"); - memset(&nicInfo, 0, sizeof nicInfo); - /* Send tools version. */ if (!GuestInfoUpdateVmdb(ctx, INFO_BUILD_NUMBER, BUILD_NUMBER)) { /* @@ -364,20 +366,20 @@ GuestInfoGather(gpointer data) /* Get NIC information. */ if (!GuestInfo_GetNicInfo(&nicInfo)) { g_warning("Failed to get nic info.\n"); - } else if (NicInfoChanged(&nicInfo)) { - if (GuestInfoUpdateVmdb(ctx, INFO_IPADDRESS, &nicInfo)) { + } else if (NicInfoChanged(nicInfo)) { + if (GuestInfoUpdateVmdb(ctx, INFO_IPADDRESS, nicInfo)) { /* * Update the cache. Release the memory previously used by the cache, * and copy the new information into the cache. */ - VMX_XDR_FREE(xdr_GuestNicList, &gInfoCache.nicInfo); + GuestInfo_FreeNicInfo(gInfoCache.nicInfo); gInfoCache.nicInfo = nicInfo; } else { g_warning("Failed to update VMDB.\n"); } } else { g_debug("Nic info not changed.\n"); - VMX_XDR_FREE(xdr_GuestNicList, &nicInfo); + GuestInfo_FreeNicInfo(nicInfo); } /* Send the uptime to VMX so that it can detect soft resets. */ @@ -419,17 +421,15 @@ GuestInfoGather(gpointer data) *---------------------------------------------------------------------- */ -Bool -GuestInfoConvertNicInfoToNicInfoV1(GuestNicList *info, // IN +void +GuestInfoConvertNicInfoToNicInfoV1(NicInfoV3 *info, // IN GuestNicInfoV1 *infoV1) // OUT { uint32 maxNics; u_int i; - if ((NULL == info) || - (NULL == infoV1)) { - return FALSE; - } + ASSERT(info); + ASSERT(infoV1); maxNics = MIN(info->nics.nics_len, MAX_NICS); infoV1->numNicEntries = maxNics; @@ -440,7 +440,7 @@ GuestInfoConvertNicInfoToNicInfoV1(GuestNicList *info, // IN XDRUTIL_FOREACH(i, info, nics) { u_int j; uint32 maxIPs; - GuestNic *nic = XDRUTIL_GETITEM(info, nics, i); + GuestNicV3 *nic = XDRUTIL_GETITEM(info, nics, i); Str_Strcpy(infoV1->nicList[i].macAddress, nic->macAddress, @@ -450,18 +450,20 @@ GuestInfoConvertNicInfoToNicInfoV1(GuestNicList *info, // IN infoV1->nicList[i].numIPs = 0; XDRUTIL_FOREACH(j, nic, ips) { - VmIpAddress *ip = XDRUTIL_GETITEM(nic, ips, j); + IpAddressEntry *ip = XDRUTIL_GETITEM(nic, ips, j); + TypedIpAddress *typedIp = &ip->ipAddressAddr; + + if (typedIp->ipAddressAddrType != IAT_IPV4) { + continue; + } - if (strlen(ip->ipAddress) < sizeof infoV1->nicList[i].ipAddress[j]) { - Str_Strcpy(infoV1->nicList[i].ipAddress[j], - ip->ipAddress, - sizeof infoV1->nicList[i].ipAddress[j]); + if (NetUtil_InetNToP(AF_INET, typedIp->ipAddressAddr.InetAddress_val, + infoV1->nicList[i].ipAddress[j], + sizeof infoV1->nicList[i].ipAddress[j])) { infoV1->nicList[i].numIPs++; if (infoV1->nicList[i].numIPs == maxIPs) { break; } - } else { - g_debug("Ignoring IPV6 address for compatibility.\n"); } } @@ -472,8 +474,6 @@ GuestInfoConvertNicInfoToNicInfoV1(GuestNicList *info, // IN break; } } - - return TRUE; } @@ -538,72 +538,104 @@ GuestInfoUpdateVmdb(ToolsAppCtx *ctx, // IN: Application context case INFO_IPADDRESS: { - static Bool isCmdV1 = FALSE; + static NicInfoVersion supportedVersion = NIC_INFO_V3; + NicInfoV3 *nicInfoV3 = (NicInfoV3 *)info; char *reply = NULL; size_t replyLen; Bool status; - if (FALSE == isCmdV1) { - /* 13 = max size of string representation of an int + 3 spaces. */ - char request[sizeof GUEST_INFO_COMMAND + 13]; - GuestNicProto message; - XDR xdrs; - - if (DynXdr_Create(&xdrs) == NULL) { - return FALSE; - } +nicinfo_fsm: + switch (supportedVersion) { + case NIC_INFO_V3: + case NIC_INFO_V2: + { + /* + * 13 = max size of string representation of an int + 3 spaces. + * XXX Ditch the magic numbers. + */ + char request[sizeof GUEST_INFO_COMMAND + 13]; + GuestNicProto message = {0}; + GuestNicList *nicList = NULL; + NicInfoVersion fallbackVersion; + XDR xdrs; + + if (DynXdr_Create(&xdrs) == NULL) { + return FALSE; + } - /* Add the RPC preamble: message name, and type. */ - Str_Sprintf(request, sizeof request, "%s %d ", - GUEST_INFO_COMMAND, INFO_IPADDRESS_V2); + /* Add the RPC preamble: message name, and type. */ + Str_Sprintf(request, sizeof request, "%s %d ", + GUEST_INFO_COMMAND, INFO_IPADDRESS_V2); + + /* + * Fill in message according to the version we'll attempt. Also + * note which version we'll fall back to should the VMX reject + * our update. + */ + if (supportedVersion == NIC_INFO_V3) { + message.ver = NIC_INFO_V3; + message.GuestNicProto_u.nicInfoV3 = nicInfoV3; + + fallbackVersion = NIC_INFO_V2; + } else { + nicList = NicInfoV3ToV2(nicInfoV3); + message.ver = NIC_INFO_V2; + message.GuestNicProto_u.nicsV2 = nicList; + + fallbackVersion = NIC_INFO_V1; + } - message.ver = NIC_INFO_V2; - message.GuestNicProto_u.nicsV2 = info; + /* Write preamble and serialized nic info to XDR stream. */ + if (!DynXdr_AppendRaw(&xdrs, request, strlen(request)) || + !xdr_GuestNicProto(&xdrs, &message)) { + g_warning("Error serializing nic info v2 data."); + DynXdr_Destroy(&xdrs, TRUE); + return FALSE; + } - /* Write preamble and serialized nic info to XDR stream. */ - if (!DynXdr_AppendRaw(&xdrs, request, strlen(request)) || - !xdr_GuestNicProto(&xdrs, &message)) { - g_warning("Error serializing nic info v2 data."); + status = RpcChannel_Send(ctx->rpc, + DynXdr_Get(&xdrs), + xdr_getpos(&xdrs), + &reply, + &replyLen); DynXdr_Destroy(&xdrs, TRUE); - return FALSE; - } - status = RpcChannel_Send(ctx->rpc, - DynXdr_Get(&xdrs), - xdr_getpos(&xdrs), - &reply, - &replyLen); - DynXdr_Destroy(&xdrs, TRUE); - if (!status) { - g_warning("Failed to send V2 nic info message.\n"); - } + if (nicList) { + free(nicList); + nicList = NULL; + } - if (g_key_file_get_boolean(ctx->config, "guestinfo", "printNicInfo", NULL)) { - PrintNicInfo((GuestNicList *) info, - (int (*)(const char *fmt, ...)) RpcVMX_Log); + if (!status) { + g_warning("NicInfo update failed: version %u, reply \"%s\".\n", + supportedVersion, reply); + supportedVersion = fallbackVersion; + vm_free(reply); + reply = NULL; + goto nicinfo_fsm; + } } - } else { - status = FALSE; - } - if (!status) { - /* - * Could be that we are talking to the old protocol that GuestNicInfo is - * still fixed size. Another try to send the fixed sized Nic info. - */ - char request[sizeof (GuestNicInfoV1) + sizeof GUEST_INFO_COMMAND + + break; + + case NIC_INFO_V1: + { + /* + * Could be that we are talking to the old protocol that + * GuestNicInfo is still fixed size. Another try to send the + * fixed sized Nic info. + */ + char request[sizeof (GuestNicInfoV1) + sizeof GUEST_INFO_COMMAND + 2 + /* 2 bytes are for digits of infotype. */ 3 * sizeof (char)]; /* 3 spaces */ - GuestNicInfoV1 nicInfo; + GuestNicInfoV1 nicInfo; + + Str_Sprintf(request, + sizeof request, + "%s %d ", + GUEST_INFO_COMMAND, + INFO_IPADDRESS); + + GuestInfoConvertNicInfoToNicInfoV1(nicInfoV3, &nicInfo); - vm_free(reply); - reply = NULL; - - Str_Sprintf(request, - sizeof request, - "%s %d ", - GUEST_INFO_COMMAND, - INFO_IPADDRESS); - if (GuestInfoConvertNicInfoToNicInfoV1(info, &nicInfo)) { memcpy(request + strlen(request), &nicInfo, sizeof(GuestNicInfoV1)); @@ -617,15 +649,16 @@ GuestInfoUpdateVmdb(ToolsAppCtx *ctx, // IN: Application context &replyLen); g_debug("Just sent fixed sized nic info message.\n"); + if (!status) { g_debug("Failed to update fixed sized nic information\n"); vm_free(reply); return FALSE; } - isCmdV1 = TRUE; - } else { - return FALSE; } + break; + default: + NOT_REACHED(); } g_debug("Updated new NIC information\n"); @@ -831,14 +864,14 @@ SetGuestInfo(ToolsAppCtx *ctx, // IN: application context *----------------------------------------------------------------------------- */ -GuestNic * -GuestInfoFindMacAddress(GuestNicList *nicInfo, // IN/OUT +GuestNicV3 * +GuestInfoFindMacAddress(NicInfoV3 *nicInfo, // IN/OUT const char *macAddress) // IN { u_int i; for (i = 0; i < nicInfo->nics.nics_len; i++) { - GuestNic *nic = &nicInfo->nics.nics_val[i]; + GuestNicV3 *nic = &nicInfo->nics.nics_val[i]; if (strncmp(nic->macAddress, macAddress, NICINFO_MAC_LEN) == 0) { return nic; } @@ -868,10 +901,18 @@ GuestInfoFindMacAddress(GuestNicList *nicInfo, // IN/OUT */ Bool -NicInfoChanged(GuestNicList *nicInfo) // IN +NicInfoChanged(NicInfoV3 *nicInfo) // IN { u_int i; - GuestNicList *cachedNicInfo = &gInfoCache.nicInfo; + NicInfoV3 *cachedNicInfo = gInfoCache.nicInfo; + + if (!cachedNicInfo) { + return TRUE; + } + + /* + * XXX Add routing, DNS, WINS comparisons. + */ if (cachedNicInfo->nics.nics_len != nicInfo->nics.nics_len) { g_debug("Number of nics has changed\n"); @@ -880,8 +921,8 @@ NicInfoChanged(GuestNicList *nicInfo) // IN for (i = 0; i < cachedNicInfo->nics.nics_len; i++) { u_int j; - GuestNic *cachedNic = &cachedNicInfo->nics.nics_val[i]; - GuestNic *matchedNic; + GuestNicV3 *cachedNic = &cachedNicInfo->nics.nics_val[i]; + GuestNicV3 *matchedNic; /* Find the corresponding nic in the new nic info. */ matchedNic = GuestInfoFindMacAddress(nicInfo, cachedNic->macAddress); @@ -899,15 +940,24 @@ NicInfoChanged(GuestNicList *nicInfo) // IN /* Which IP addresses have been modified for this NIC? */ for (j = 0; j < cachedNic->ips.ips_len; j++) { - VmIpAddress *cachedIp = &cachedNic->ips.ips_val[j]; + TypedIpAddress *cachedIp = &cachedNic->ips.ips_val[j].ipAddressAddr; Bool foundIP = FALSE; + ssize_t cmpsz = + cachedIp->ipAddressAddrType == IAT_IPV4 ? 4 : + cachedIp->ipAddressAddrType == IAT_IPV6 ? 16 : + -1; u_int k; + /* XXX */ + ASSERT(cmpsz != -1); + for (k = 0; k < matchedNic->ips.ips_len; k++) { - VmIpAddress *matchedIp = &matchedNic->ips.ips_val[k]; - if (0 == strncmp(cachedIp->ipAddress, - matchedIp->ipAddress, - NICINFO_MAX_IP_LEN)) { + TypedIpAddress *matchedIp = + &matchedNic->ips.ips_val[k].ipAddressAddr; + if (cachedIp->ipAddressAddrType == matchedIp->ipAddressAddrType && + memcmp(cachedIp->ipAddressAddr.InetAddress_val, + matchedIp->ipAddressAddr.InetAddress_val, + cmpsz) == 0) { foundIP = TRUE; break; } @@ -915,9 +965,11 @@ NicInfoChanged(GuestNicList *nicInfo) // IN if (FALSE == foundIP) { /* This ip address couldn't be found and has been modified. */ +#if 0 g_debug("MAC address %s, ipaddress %s deleted\n", cachedNic->macAddress, cachedIp->ipAddress); +#endif return TRUE; } @@ -929,56 +981,6 @@ NicInfoChanged(GuestNicList *nicInfo) // IN } -/* - *---------------------------------------------------------------------------- - * - * PrintNicInfo -- - * - * Print NIC info struct using the specified print function. - * - * Results: - * Sum of return values of print function (for printf, this will be the - * number of characters printed). - * - * Side effects: - * None. - * - *---------------------------------------------------------------------------- - */ - -int -PrintNicInfo(GuestNicList *nicInfo, // IN - int (*PrintFunc)(const char *, ...)) // IN -{ - int ret = 0; - u_int i = 0; - - ret += PrintFunc("NicInfo: count: %ud\n", nicInfo->nics.nics_len); - for (i = 0; i < nicInfo->nics.nics_len; i++) { - u_int j; - GuestNic *nic = &nicInfo->nics.nics_val[i]; - - ret += PrintFunc("NicInfo: nic [%d/%d] mac: %s", - i+1, - nicInfo->nics.nics_len, - nic->macAddress); - - for (j = 0; j < nic->ips.ips_len; j++) { - VmIpAddress *ipAddress = &nic->ips.ips_val[j]; - - ret += PrintFunc("NicInfo: nic [%d/%d] IP [%d/%d]: %s", - i+1, - nicInfo->nics.nics_len, - j+1, - nic->ips.ips_len, - ipAddress->ipAddress); - } - } - - return ret; -} - - /* *---------------------------------------------------------------------- * @@ -1074,8 +1076,67 @@ GuestInfoClearCache(void) gInfoCache.value[i][0] = 0; } - VMX_XDR_FREE(xdr_GuestNicList, &gInfoCache.nicInfo); - memset(&gInfoCache.nicInfo, 0, sizeof gInfoCache.nicInfo); + GuestInfo_FreeNicInfo(gInfoCache.nicInfo); + gInfoCache.nicInfo = NULL; +} + + +/* + *********************************************************************** + * NicInfoV3ToV2 -- */ /** + * + * @brief Converts the NicInfoV3 NIC list to a GuestNicList. + * + * @note This function performs @e shallow copies of things such as + * IP address array, making it depend on the source NicInfoV3. + * In other words, do @e not free NicInfoV3 before freeing the + * returned pointer. + * + * @param[in] infoV3 Source NicInfoV3 container. + * + * @return Pointer to a GuestNicList. Caller should free it using + * plain ol' @c free. + * + *********************************************************************** + */ + +static GuestNicList * +NicInfoV3ToV2(const NicInfoV3 *infoV3) +{ + GuestNicList *nicList; + unsigned int i, j; + + nicList = Util_SafeCalloc(sizeof *nicList, 1); + + XDRUTIL_ARRAYAPPEND(nicList, nics, infoV3->nics.nics_len); + XDRUTIL_FOREACH(i, infoV3, nics) { + GuestNicV3 *nic = XDRUTIL_GETITEM(infoV3, nics, i); + GuestNic *oldNic = XDRUTIL_GETITEM(nicList, nics, i); + + Str_Strcpy(oldNic->macAddress, nic->macAddress, sizeof oldNic->macAddress); + + XDRUTIL_ARRAYAPPEND(oldNic, ips, nic->ips.ips_len); + + XDRUTIL_FOREACH(j, nic, ips) { + IpAddressEntry *ipEntry = XDRUTIL_GETITEM(nic, ips, j); + TypedIpAddress *ip = &ipEntry->ipAddressAddr; + VmIpAddress *oldIp = XDRUTIL_GETITEM(oldNic, ips, j); + + /* XXX */ + oldIp->addressFamily = (ip->ipAddressAddrType == IAT_IPV4) ? + NICINFO_ADDR_IPV4 : NICINFO_ADDR_IPV6; + + NetUtil_InetNToP(ip->ipAddressAddrType == IAT_IPV4 ? + AF_INET : AF_INET6, + ip->ipAddressAddr.InetAddress_val, oldIp->ipAddress, + sizeof oldIp->ipAddress); + + Str_Sprintf(oldIp->subnetMask, sizeof oldIp->subnetMask, "%u", + ipEntry->ipAddressPrefixLength); + } + } + + return nicList; } @@ -1118,9 +1179,11 @@ ToolsOnLoad(ToolsAppCtx *ctx) vmResumed = FALSE; /* Add the first timer event. */ - src = g_timeout_source_new(GUESTINFO_TIME_INTERVAL_MSEC * 10); - VMTOOLSAPP_ATTACH_SOURCE(ctx, src, GuestInfoGather, ctx, NULL); - g_source_unref(src); + if (ctx->rpc) { + src = g_timeout_source_new(GUESTINFO_TIME_INTERVAL_MSEC * 10); + VMTOOLSAPP_ATTACH_SOURCE(ctx, src, GuestInfoGather, ctx, NULL); + g_source_unref(src); + } return ®Data; } diff --git a/open-vm-tools/services/plugins/hgfsServer/hgfsPlugin.c b/open-vm-tools/services/plugins/hgfsServer/hgfsPlugin.c index 96ece869c..507150005 100644 --- a/open-vm-tools/services/plugins/hgfsServer/hgfsPlugin.c +++ b/open-vm-tools/services/plugins/hgfsServer/hgfsPlugin.c @@ -150,7 +150,7 @@ HgfsServerCapReg(gpointer src, * * Long story short, we shouldn't care if this function fails. */ - if (!RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) { + if (ctx->rpc && !RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) { g_warning("Setting HGFS server capability failed!\n"); } diff --git a/open-vm-tools/services/plugins/resolutionSet/resolutionSet.c b/open-vm-tools/services/plugins/resolutionSet/resolutionSet.c index 974372dee..6c682500c 100644 --- a/open-vm-tools/services/plugins/resolutionSet/resolutionSet.c +++ b/open-vm-tools/services/plugins/resolutionSet/resolutionSet.c @@ -369,7 +369,7 @@ ResolutionServerCapReg(ToolsAppCtx *ctx, appName, set); - if (!RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) { + if (ctx->rpc && !RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) { g_warning("Setting resolution_server capability failed!\n"); } diff --git a/open-vm-tools/services/plugins/vix/Makefile.am b/open-vm-tools/services/plugins/vix/Makefile.am index 687e2192a..4cb2df436 100644 --- a/open-vm-tools/services/plugins/vix/Makefile.am +++ b/open-vm-tools/services/plugins/vix/Makefile.am @@ -36,6 +36,7 @@ libvix_la_SOURCES = libvix_la_SOURCES += foundryToolsDaemon.c libvix_la_SOURCES += vixPlugin.c libvix_la_SOURCES += $(top_srcdir)/lib/vixTools/vixTools.c +libvix_la_SOURCES += $(top_srcdir)/lib/hgfsHelper/hgfsHelperPosix.c if HAVE_X11 install-data-hook: diff --git a/open-vm-tools/services/plugins/vix/foundryToolsDaemon.c b/open-vm-tools/services/plugins/vix/foundryToolsDaemon.c index 72f7ff905..26eacf87b 100644 --- a/open-vm-tools/services/plugins/vix/foundryToolsDaemon.c +++ b/open-vm-tools/services/plugins/vix/foundryToolsDaemon.c @@ -88,10 +88,6 @@ #include "hgfsDevLinux.h" #endif -#ifndef __FreeBSD__ -#include "netutil.h" -#endif - /* Only Win32 and Linux use impersonation functions. */ #if !defined(__FreeBSD__) && !defined(sun) #include "impersonate.h" diff --git a/open-vm-tools/services/plugins/vmbackup/stateMachine.c b/open-vm-tools/services/plugins/vmbackup/stateMachine.c index d2e63060c..a9f3f7d5e 100644 --- a/open-vm-tools/services/plugins/vmbackup/stateMachine.c +++ b/open-vm-tools/services/plugins/vmbackup/stateMachine.c @@ -179,7 +179,6 @@ VmBackupFinalize(void) { g_debug("*** %s\n", __FUNCTION__); ASSERT(gBackupState != NULL); - ASSERT(gBackupState->machineState == VMBACKUP_MSTATE_IDLE); if (gBackupState->currentOp != NULL) { VmBackup_Cancel(gBackupState->currentOp); diff --git a/open-vm-tools/services/vmtoolsd/mainLoop.c b/open-vm-tools/services/vmtoolsd/mainLoop.c index 6e346663a..b68c8c742 100644 --- a/open-vm-tools/services/vmtoolsd/mainLoop.c +++ b/open-vm-tools/services/vmtoolsd/mainLoop.c @@ -74,10 +74,7 @@ ToolsCoreInitializeDebug(ToolsServiceState *state) /** - * Reloads the config file and re-configure the logging subsystem if the - * log file was updated. If the config file is being loaded for the first - * time, try to upgrade it to the new version if an old version is - * detected. + * Timer callback that just calls ToolsCore_ReloadConfig(). * * @param[in] clientData Service state. * @@ -85,44 +82,9 @@ ToolsCoreInitializeDebug(ToolsServiceState *state) */ static gboolean -ToolsCoreReloadConfig(gpointer clientData) +ToolsCoreConfFileCb(gpointer clientData) { - ToolsServiceState *state = clientData; - char *confFile = state->configFile; - gboolean loaded = TRUE; - - if (confFile == NULL) { - confFile = VMTools_GetToolsConfFile(); - } - - if (state->ctx.config == NULL) { - state->ctx.config = VMTools_LoadConfig(confFile, - G_KEY_FILE_NONE, - state->mainService); - state->configMtime = time(NULL); - if (state->ctx.config == NULL) { - /* Couldn't load the config file. Just create an empty dictionary. */ - state->ctx.config = g_key_file_new(); - } - } else if (VMTools_ReloadConfig(confFile, - G_KEY_FILE_NONE, - &state->ctx.config, - &state->configMtime)) { - g_debug("Config file reloaded.\n"); - } else { - loaded = FALSE; - } - - if (loaded) { - VMTools_ConfigLogging(state->ctx.config); - if (state->log) { - VMTools_EnableLogging(state->log); - } - } - - if (state->configFile == NULL) { - g_free(confFile); - } + ToolsCore_ReloadConfig(clientData, FALSE); return TRUE; } @@ -231,6 +193,60 @@ ToolsCore_GetTcloName(ToolsServiceState *state) } +/** + * Reloads the config file and re-configure the logging subsystem if the + * log file was updated. If the config file is being loaded for the first + * time, try to upgrade it to the new version if an old version is + * detected. + * + * @param[in] state Service state. + * @param[in] force Whether to force reconfiguration of the logging + * subsystem. + */ + +void +ToolsCore_ReloadConfig(ToolsServiceState *state, + gboolean force) +{ + char *confFile; + gboolean loaded = TRUE; + + VMTools_SetDefaultLogDomain(state->name); + + confFile = g_strdup(state->configFile); + if (confFile == NULL) { + confFile = VMTools_GetToolsConfFile(); + } + + if (state->ctx.config == NULL) { + state->ctx.config = VMTools_LoadConfig(confFile, + G_KEY_FILE_NONE, + state->mainService); + state->configMtime = time(NULL); + if (state->ctx.config == NULL) { + /* Couldn't load the config file. Just create an empty dictionary. */ + state->ctx.config = g_key_file_new(); + } + } else if (VMTools_ReloadConfig(confFile, + G_KEY_FILE_NONE, + &state->ctx.config, + &state->configMtime)) { + g_debug("Config file reloaded.\n"); + } else { + loaded = FALSE; + } + + if (force || loaded) { + VMTools_ConfigLogging(state->ctx.config); + if (state->log) { + VMTools_EnableLogging(state->log); + } + } + + g_free(confFile); +} + + /** * Performs any initial setup steps for the service's main loop. * @@ -248,8 +264,7 @@ ToolsCore_Setup(ToolsServiceState *state) g_thread_init(NULL); } - VMTools_SetDefaultLogDomain(state->name); - ToolsCoreReloadConfig(state); + ToolsCore_ReloadConfig(state, FALSE); /* Initializes the app context. */ gctx = g_main_context_default(); @@ -273,7 +288,11 @@ ToolsCore_Setup(ToolsServiceState *state) goto error; } - if (!state->ctx.rpc->start(state->ctx.rpc)) { + /* + * Start the RPC channel if it's been created. The channel may be NULL if this is + * not running in the context of a VM. + */ + if (state->ctx.rpc && !state->ctx.rpc->start(state->ctx.rpc)) { goto error; } @@ -310,7 +329,16 @@ exit: int ToolsCore_Run(ToolsServiceState *state) { - g_timeout_add(CONF_POLL_TIME * 10, ToolsCoreReloadConfig, state); + /* + * If there's no RPC channel (not in a VM) then there's no point in trying to + * run the loop, just exit with a '0' return status (see bug 297528 for why '0'). + */ + if (!state->ctx.rpc) { + return 0; + } + + g_timeout_add(CONF_POLL_TIME * 10, ToolsCoreConfFileCb, state); + #if defined(__APPLE__) ToolsCore_CFRunLoop(state); #else diff --git a/open-vm-tools/services/vmtoolsd/mainPosix.c b/open-vm-tools/services/vmtoolsd/mainPosix.c index ded73ff04..498ba0120 100644 --- a/open-vm-tools/services/vmtoolsd/mainPosix.c +++ b/open-vm-tools/services/vmtoolsd/mainPosix.c @@ -42,6 +42,27 @@ VM_EMBED_VERSION(VMTOOLSD_VERSION_STRING); static ToolsServiceState gState = { NULL, }; + +/** + * Reloads the service configuration - including forcing rotation of log + * files by reinitializing the logging subsystem. + * + * @param[in] info Unused. + * @param[in] data Service state. + * + * @return TRUE + */ + +static gboolean +ToolsCoreSigHUPCb(const siginfo_t *info, + gpointer data) +{ + VMTools_ResetLogging(TRUE); + ToolsCore_ReloadConfig(data, TRUE); + return TRUE; +} + + /** * Handles a signal that would terminate the process. Asks the main loop * to exit nicely. @@ -162,7 +183,7 @@ main(int argc, src = VMTools_NewSignalSource(SIGHUP); VMTOOLSAPP_ATTACH_SOURCE(&gState.ctx, src, - ToolsCoreSigHandler, gState.ctx.mainLoop, NULL); + ToolsCoreSigHUPCb, &gState, NULL); g_source_unref(src); src = VMTools_NewSignalSource(SIGINT); diff --git a/open-vm-tools/services/vmtoolsd/pluginMgr.c b/open-vm-tools/services/vmtoolsd/pluginMgr.c index fc8f083f9..b27a4ff2e 100644 --- a/open-vm-tools/services/vmtoolsd/pluginMgr.c +++ b/open-vm-tools/services/vmtoolsd/pluginMgr.c @@ -603,7 +603,9 @@ ToolsCore_UnloadPlugins(ToolsServiceState *state) &pcaps); if (pcaps != NULL) { - ToolsCore_SetCapabilities(state->ctx.rpc, pcaps, FALSE); + if (state->ctx.rpc) { + ToolsCore_SetCapabilities(state->ctx.rpc, pcaps, FALSE); + } g_array_free(pcaps, TRUE); } diff --git a/open-vm-tools/services/vmtoolsd/toolsCoreInt.h b/open-vm-tools/services/vmtoolsd/toolsCoreInt.h index 3e12654c6..827418127 100644 --- a/open-vm-tools/services/vmtoolsd/toolsCoreInt.h +++ b/open-vm-tools/services/vmtoolsd/toolsCoreInt.h @@ -112,6 +112,10 @@ ToolsCore_InitRpc(ToolsServiceState *state); gboolean ToolsCore_LoadPlugins(ToolsServiceState *state); +void +ToolsCore_ReloadConfig(ToolsServiceState *state, + gboolean force); + void ToolsCore_RegisterPlugins(ToolsServiceState *state); diff --git a/open-vm-tools/services/vmtoolsd/toolsRpc.c b/open-vm-tools/services/vmtoolsd/toolsRpc.c index 3f85401f8..8ca3628c8 100644 --- a/open-vm-tools/services/vmtoolsd/toolsRpc.c +++ b/open-vm-tools/services/vmtoolsd/toolsRpc.c @@ -238,34 +238,38 @@ ToolsCore_InitRpc(ToolsServiceState *state) } else { /* * Currently we try to bring up an RpcIn channel, which will only run - * inside a Virtual Machine. We want to exit with a "success" status - * if this check fails, though. (See bug 297528 for why.) + * inside a Virtual Machine. Some plugins may still want to launch and at + * least begin even in not in a VM (typically because the installation is dual + * purposed between a VM and Bootcamp) - plugins may wish to undo some state + * if not in a VM. * * XXX: this should be relaxed when we try to bring up a VMCI or TCP channel. */ if (!state->ctx.isVMware) { g_warning("The %s service needs to run inside a virtual machine.\n", state->name); - exit(0); + state->ctx.rpc = NULL; + } else { + state->ctx.rpc = RpcChannel_NewBackdoorChannel(mainCtx); } - - state->ctx.rpc = RpcChannel_NewBackdoorChannel(mainCtx); app = ToolsCore_GetTcloName(state); ASSERT(app != NULL); } - RpcChannel_Setup(state->ctx.rpc, - app, - mainCtx, - &state->ctx, - ToolsCoreCheckReset, - state); - - /* Register the "built in" RPCs. */ - for (i = 0; i < ARRAYSIZE(rpcs); i++) { - RpcChannelCallback *rpc = &rpcs[i]; - rpc->clientData = state; - RpcChannel_RegisterCallback(state->ctx.rpc, rpc); + if (state->ctx.rpc) { + RpcChannel_Setup(state->ctx.rpc, + app, + mainCtx, + &state->ctx, + ToolsCoreCheckReset, + state); + + /* Register the "built in" RPCs. */ + for (i = 0; i < ARRAYSIZE(rpcs); i++) { + RpcChannelCallback *rpc = &rpcs[i]; + rpc->clientData = state; + RpcChannel_RegisterCallback(state->ctx.rpc, rpc); + } } return TRUE; diff --git a/open-vm-tools/tests/Makefile.am b/open-vm-tools/tests/Makefile.am index a09fde2a6..221ddbc0b 100644 --- a/open-vm-tools/tests/Makefile.am +++ b/open-vm-tools/tests/Makefile.am @@ -19,6 +19,7 @@ SUBDIRS = SUBDIRS += vmrpcdbg SUBDIRS += testDebug SUBDIRS += testPlugin +SUBDIRS += testVmblock install-exec-local: rm -f $(DESTDIR)$(TEST_PLUGIN_INSTALLDIR)/*.a diff --git a/open-vm-tools/tests/testVmblock/COPYING b/open-vm-tools/tests/testVmblock/COPYING new file mode 100644 index 000000000..09f465ab7 --- /dev/null +++ b/open-vm-tools/tests/testVmblock/COPYING @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library 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; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/open-vm-tools/tests/testVmblock/Makefile.am b/open-vm-tools/tests/testVmblock/Makefile.am new file mode 100644 index 000000000..13a6b45ae --- /dev/null +++ b/open-vm-tools/tests/testVmblock/Makefile.am @@ -0,0 +1,41 @@ +################################################################################ +### Copyright 2009 VMware, Inc. All rights reserved. +### +### This program is free software; you can redistribute it and/or modify +### it under the terms of version 2 of the GNU General Public License as +### published by the Free Software Foundation. +### +### 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 +### GNU General Public License for more details. +### +### You should have received a copy of the GNU 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 +################################################################################ + +noinst_PROGRAMS = vmware-testvmblock-legacy +noinst_PROGRAMS += vmware-testvmblock-manual-legacy + +if HAVE_FUSE + noinst_PROGRAMS += vmware-testvmblock-fuse + noinst_PROGRAMS += vmware-testvmblock-manual-fuse +endif + +AM_CFLAGS = +AM_CFLAGS += -DVMX86_DEVEL +AM_CFLAGS += -DVMX86_DEBUG + +AM_LDFLAGS = +AM_LDFLAGS += -lpthread + +vmware_testvmblock_legacy_SOURCES = vmblocktest.c + +vmware_testvmblock_manual_legacy_SOURCES = manual-blocker.c + +vmware_testvmblock_fuse_CFLAGS = $(AM_CFLAGS) -Dvmblock_fuse +vmware_testvmblock_fuse_SOURCES = vmblocktest.c + +vmware_testvmblock_manual_fuse_CFLAGS = $(AM_CFLAGS) -Dvmblock_fuse +vmware_testvmblock_manual_fuse_SOURCES = manual-blocker.c diff --git a/open-vm-tools/tests/testVmblock/manual-blocker.c b/open-vm-tools/tests/testVmblock/manual-blocker.c new file mode 100644 index 000000000..52dbb0ae0 --- /dev/null +++ b/open-vm-tools/tests/testVmblock/manual-blocker.c @@ -0,0 +1,103 @@ +/********************************************************* + * 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. + * + *********************************************************/ + +/* + * manual-blocker.c -- + * + * A small test program for manually manipulating vmblock. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "vmblock_user.h" + + +/* + *----------------------------------------------------------------------------- + * + * main -- + * + * Takes the target file to block as a command line arg. Sits in a loop + * waiting for commands. + * + * Results: + * Returns 0 on success and nonzero on failure. + * + * Side effects: + * None/all. + * + *----------------------------------------------------------------------------- + */ + +int +main(int argc, + char *argv[]) +{ + int status; + char op; + + if (argc < 2 || + strcmp(argv[1], "-h") == 0 || + strcmp(argv[1], "--help") == 0) { + printf("Usage: %s \n", argv[0]); + puts("a to Add a block, d to Delete a block, or l to List blocks (to" + " vmblock's log).\n"); + return 1; + } + + int fd = open(VMBLOCK_DEVICE, VMBLOCK_DEVICE_MODE); + if (fd <= 0) { + perror("open"); + return 2; + } + printf("Opened " VMBLOCK_DEVICE " as fd %d.\n", fd); + + while (1) { + op = getchar(); + if (op == 'a') { + status = VMBLOCK_CONTROL(fd, VMBLOCK_ADD_FILEBLOCK, argv[1]); + if (status != 0) { + perror(NULL); + } else { + printf("%s blocked.\n", argv[1]); + } + } else if (op == 'd') { + status = VMBLOCK_CONTROL(fd, VMBLOCK_DEL_FILEBLOCK, argv[1]); + if (status != 0) { + perror(NULL); + } else { + printf("%s unblocked.\n", argv[1]); + } + } else if (op == 'l') { + status = VMBLOCK_CONTROL(fd, VMBLOCK_LIST_FILEBLOCKS, argv[1]); + if (status != 0) { + perror(NULL); + } else { + printf("Check vmblock's log for list of blocks.\n"); + } + } + } + + return 0; +} diff --git a/open-vm-tools/tests/testVmblock/vmblocktest.c b/open-vm-tools/tests/testVmblock/vmblocktest.c new file mode 100644 index 000000000..ed63def6b --- /dev/null +++ b/open-vm-tools/tests/testVmblock/vmblocktest.c @@ -0,0 +1,647 @@ +/********************************************************* + * Copyright (C) 2006 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. + * + *********************************************************/ + +/* + * vmblocktest.c -- + * + * Test program for the vmblock file system. Ensures correctness and + * stability. + * + */ + +#if !defined(linux) && !defined(sun) && !defined(__FreeBSD__) && !defined(vmblock_fuse) +# error "vmblocktest.c needs to be ported to your OS." +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef sun +# include +#endif + +#include "vmblock_user.h" +#include "vm_basic_types.h" + +#define BLOCKROOT VMBLOCK_MOUNT_POINT "/" +#define CONTROLFILE VMBLOCK_DEVICE +#define CONTROLFILE_MODE VMBLOCK_DEVICE_MODE +#define REALROOT "/tmp/VMwareDnD/" +#define FILENAME "/foo" +#define ACCESSORFULLNAME(dir) BLOCKROOT dir FILENAME +#define BLOCKERFULLNAME(dir) REALROOT dir + +#define lprintf(...) \ + do { \ + pthread_mutex_lock(&print_lock); \ + printf(__VA_ARGS__); \ + fflush(stdout); \ + pthread_mutex_unlock(&print_lock); \ + } while(0) + +#define lfprintf(stream, ...) \ + do { \ + pthread_mutex_lock(&print_lock); \ + fprintf(stream, __VA_ARGS__); \ + fflush(stream); \ + pthread_mutex_unlock(&print_lock); \ + } while(0) + +#define Log(fmt, args...) lprintf(fmt, ## args) +#define ERROR(fmt, args...) lfprintf(stderr, fmt, ## args) +#define THREAD_LOG(fmt, args...) lprintf(" (%lx) " fmt, (unsigned long)pthread_self(), ## args) +#define THREAD_ERROR(fmt, args...) lfprintf(stderr, " (%"FMTPID") " fmt, getpid(), ## args) + +#if defined (linux) || defined(__FreeBSD__) +# define os_thread_yield() sched_yield() +#elif defined(sun) +# define os_thread_yield() yield() +#endif + +/* + * This program may optionally throttle accessor thread generation + * via POSIX semaphores. + */ +#if defined(USE_SEMAPHORES) +sem_t sem; +# define SEM_THREADS (unsigned int)10 +# define SEM_INIT() sem_init(&sem, 0, SEM_THREADS) +# define SEM_DESTROY() sem_destroy(&sem) +# define SEM_WAIT() sem_wait(&sem) +# define SEM_POST() sem_post(&sem) +# define PTHREAD_SEMAPHORE_CLEANUP() pthread_cleanup_push(sem_post, \ + (void *)&sem) +#else +# define SEM_INIT() +# define SEM_DESTROY() +# define SEM_WAIT() +# define SEM_POST() +# define PTHREAD_SEMAPHORE_CLEANUP() +#endif + +/* Types */ +typedef struct FileState { + /* Accessors will access the file through the vmblock namespace */ + char *accessorName; + /* The blocker will add blocks using the real file's name */ + char *blockerName; + Bool blocked; + unsigned int waiters; +} FileState; + +typedef struct ThreadInfo { + int blockFd; + pthread_mutex_t *lock; + FileState *files; + size_t filesArraySize; + unsigned int sleepTime; +} ThreadInfo; + +/* Variables */ +static Bool programQuit = FALSE; +static FileState files[] = { + { ACCESSORFULLNAME("0"), BLOCKERFULLNAME("0"), FALSE, 0 }, + { ACCESSORFULLNAME("1"), BLOCKERFULLNAME("1"), FALSE, 0 }, + { ACCESSORFULLNAME("2"), BLOCKERFULLNAME("2"), FALSE, 0 }, + { ACCESSORFULLNAME("3"), BLOCKERFULLNAME("3"), FALSE, 0 }, + { ACCESSORFULLNAME("4"), BLOCKERFULLNAME("4"), FALSE, 0 }, + { ACCESSORFULLNAME("5"), BLOCKERFULLNAME("5"), FALSE, 0 }, + { ACCESSORFULLNAME("6"), BLOCKERFULLNAME("6"), FALSE, 0 }, + { ACCESSORFULLNAME("7"), BLOCKERFULLNAME("7"), FALSE, 0 }, + { ACCESSORFULLNAME("8"), BLOCKERFULLNAME("8"), FALSE, 0 }, + { ACCESSORFULLNAME("9"), BLOCKERFULLNAME("9"), FALSE, 0 }, +}; + +/* Thread entry points */ +static void *blocker(void *arg); +static void *accessor(void *arg); + +/* Utility functions */ +static Bool addBlock(int fd, char const *filename); +static Bool delBlock(int fd, char const *filename); +static Bool listBlocks(int fd); +#ifdef VMBLOCK_PURGE_FILEBLOCKS +static Bool purgeBlocks(int fd); +#endif +static unsigned int getRand(unsigned int max); +static void sighandler(int sig); + +pthread_mutex_t print_lock; + +/* + *---------------------------------------------------------------------------- + * + * main -- + * + * Does all necessary setup then starts the blocker thread and continually + * starts accessor threads. + * + * Results: + * EXIT_SUCCESS and EXIT_FAILURE. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +int +main(int argc, + char *argv[]) +{ + int ret = EXIT_SUCCESS; + int i; + int blockFd; + char *progname; + pthread_t blockerThread; + pthread_mutex_t filesLock; + pthread_attr_t attr; + ThreadInfo info; + int count; + + progname = basename(argv[0]); + pthread_mutex_init(&filesLock, NULL); + + SEM_INIT(); + pthread_mutex_init(&print_lock, NULL); + + /* Open device user to add/delete blocks */ + blockFd = open(CONTROLFILE, CONTROLFILE_MODE); + if (blockFd < 0) { + ERROR("%s: could not open " CONTROLFILE "\n", progname); + exit(EXIT_FAILURE); + } + + /* Provide ability to just list blocks */ + if (argc > 1) { + if (strcmp(argv[1], "-list") == 0) { + listBlocks(blockFd); +#ifdef VMBLOCK_PURGE_FILEBLOCKS + } else if (strcmp(argv[1], "-purge") == 0) { + purgeBlocks(blockFd); +#endif + } + close(blockFd); + exit(EXIT_SUCCESS); + } + + /* Create directories/files used during test */ + for (i = 0; i < sizeof files/sizeof files[0]; i++) { + int err; + struct stat statbuf; + char buf[PATH_MAX]; + + err = stat(files[i].blockerName, &statbuf); + if (!err) { + if (S_ISDIR(statbuf.st_mode)) { + goto create_file; + } + + ERROR("%s: file [%s] already exists and is not a directory\n", + progname, files[i].blockerName); + goto exit_failure; + } + + err = mkdir(files[i].blockerName, S_IRWXU | S_IRWXG); + if (err) { + ERROR("%s: could not create [%s]\n", progname, files[i].blockerName); + goto exit_failure; + } + +create_file: + strncpy(buf, files[i].blockerName, sizeof buf); + strncat(buf, FILENAME, sizeof buf - strlen(files[i].blockerName)); + err = stat(buf, &statbuf); + if (!err) { + if (S_ISREG(statbuf.st_mode)) { + continue; + } + + ERROR("%s: file [%s] already exists and is not a regular file\n", + progname, buf); + goto exit_failure; + } + + err = creat(buf, S_IRUSR | S_IRGRP); + if (err < 0) { + ERROR("%s: could not create [%s]\n", progname, buf); + goto exit_failure; + } + + continue; + +exit_failure: + close(blockFd); + exit(EXIT_FAILURE); + } + + if (signal(SIGINT, sighandler) == SIG_ERR || + signal(SIGTERM, sighandler) == SIG_ERR) { + ERROR("%s: could not install signal handlers\n", progname); + close(blockFd); + exit(EXIT_FAILURE); + } + + /* Seems cleaner than a bunch of globals ... */ + info.blockFd = blockFd; + info.lock = &filesLock; + info.files = files; + info.filesArraySize = sizeof files/sizeof files[0]; + info.sleepTime = 1; + + /* + * Start a thread that flips a random file's state, then sleeps for a while + * and does it again. + */ + if (pthread_create(&blockerThread, NULL, blocker, &info)) { + ERROR("%s: could not create blocker thread\n", progname); + close(blockFd); + exit(EXIT_FAILURE); + } + + /* + * Start a bunch of threads that try to open a random file, check its status + * once they have it open (to make sure it is not blocked), then close it + * and exit. + */ + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + count = 0; + while (!programQuit) { + pthread_t thread; + int rv; + SEM_WAIT(); + /* Create threads until we cannot anymore */ + if ((rv = pthread_create(&thread, &attr, accessor, &info)) != 0) { + SEM_POST(); + if (rv == EAGAIN || rv == ENOMEM) { + os_thread_yield(); + continue; + } + ERROR("%s: could not create an accessor thread (%d total)\n", + progname, count); + ERROR("%s: pthread_create: %s\n", progname, strerror(rv)); + ret = EXIT_FAILURE; + break; + } + count++; + } + + Log("%s: Not creating any more accessor threads.\n", progname); + + programQuit = TRUE; + pthread_join(blockerThread, NULL); + + pthread_mutex_destroy(&filesLock); + close(blockFd); + + Log("%s: Exiting with %s.\n", + progname, ret == EXIT_SUCCESS ? "success" : "failure"); + + exit(ret); +} + + +/* + *---------------------------------------------------------------------------- + * + * blocker -- + * + * Entry point for the single blocker thread. Continuously picks a file at + * random and changes its state by adding or deleting a block on that file. + * + * Results: + * EXIT_SUCCESS and EXIT_FAILURE. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static void * +blocker(void *arg) // IN +{ + ThreadInfo *info = (ThreadInfo *)arg; + unsigned int index; + + if (!info) { + THREAD_ERROR("blocker: no thread info provided\n"); + pthread_exit((void *)EXIT_FAILURE); + } + + while (!programQuit) { + index = getRand(info->filesArraySize - 1); + + pthread_mutex_lock(info->lock); + + if (info->files[index].blocked) { + info->files[index].blocked = FALSE; + if ( !delBlock(info->blockFd, info->files[index].blockerName) ) { + THREAD_ERROR("blocker: could not delete block on [%s]\n", + info->files[index].blockerName); + goto error; + } + } else if (info->files[index].waiters == 0) { + /* + * Only add a new block if all previous waiters are done. This + * ensures we don't get incorrect error messages from accessor threads + * even though the open(2) and check are not atomic in the accessor. + */ + info->files[index].blocked = TRUE; + if ( !addBlock(info->blockFd, info->files[index].blockerName) ) { + THREAD_ERROR("blocker: could not add block on [%s]\n", + info->files[index].blockerName); + goto error; + } + } + + pthread_mutex_unlock(info->lock); + + sleep(info->sleepTime); + } + + pthread_mutex_lock(info->lock); + for (index = 0; index < info->filesArraySize; index++) { + if (info->files[index].blocked) { + info->files[index].blocked = FALSE; +#ifndef TEST_CLOSE_FD + THREAD_LOG("blocker: deleting block for [%s]\n", + info->files[index].blockerName); + if ( !delBlock(info->blockFd, info->files[index].blockerName) ) { + THREAD_ERROR("blocker: could not delete existing block on exit for [%s]\n", + info->files[index].blockerName); + } +#else + THREAD_LOG("blocker: unmarking block for [%s], left for unblock on release\n", + info->files[index].blockerName); +#endif + } + } + pthread_mutex_unlock(info->lock); + + pthread_exit(EXIT_SUCCESS); + +error: + programQuit = TRUE; + pthread_mutex_unlock(info->lock); + pthread_exit((void *)EXIT_FAILURE); +} + + +/* + *---------------------------------------------------------------------------- + * + * accessor -- + * + * Entry point for accessor threads. Picks a file at random and attempts to + * open it. Once it is opened, ensures the state of the file is not blocked + * and outputs an error message accordingly. + * + * Results: + * EXIT_SUCCESS and EXIT_FAILURE. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static void * +accessor(void *arg) // IN +{ + ThreadInfo *info = (ThreadInfo *)arg; + unsigned int index; + int fd; + uintptr_t ret = EXIT_SUCCESS; + + PTHREAD_SEMAPHORE_CLEANUP(); + + if (!info) { + THREAD_ERROR("blocker: no thread info provided\n"); + pthread_exit((void *)EXIT_FAILURE); + } + + index = getRand(info->filesArraySize - 1); + + /* + * We can't hold the lock while calling open(2), since we will deadlock + * waiting for the blocker thread to remove the block on the file. So, we + * bump the waiter count to ensure that a new block is not placed on this + * file until we have checked its state. This prevents incorrect error + * messages that would happen if the blocker placed a new block on the file + * between our open(2) call returning and acquiring the lock. + * + * The fact that we can't hold the lock through open(2) also means that it's + * not atomic with respect to checking the file's blocked flag. Given this, + * it's possible that we'll miss some errors if the block is removed after + * open(2) returns but before we check the blocked flag -- hopefully running + * this test for a very long time will be sufficient to catch these cases. + * (Having the blocker sleep increases the likelihood of seeing such + * errors.) + */ + pthread_mutex_lock(info->lock); + info->files[index].waiters++; + pthread_mutex_unlock(info->lock); + + fd = open(info->files[index].accessorName, O_RDONLY); + if (fd < 0) { + if (errno == EMFILE) { + /* We already have hit the maximum number of file descriptors */ + pthread_mutex_lock(info->lock); + info->files[index].waiters--; + pthread_mutex_unlock(info->lock); + pthread_exit((void *)EXIT_FAILURE); + } + THREAD_ERROR("accessor: could not open file [%s]\n", + info->files[index].accessorName); + THREAD_ERROR("accessor: open: %s\n", strerror(errno)); + pthread_exit((void *)EXIT_FAILURE); + } + + pthread_mutex_lock(info->lock); + info->files[index].waiters--; + + if (info->files[index].blocked) { + THREAD_ERROR("accessor: [ERROR] accessed file [%s] while blocked (%d)\n", + info->files[index].accessorName, info->files[index].blocked); + ret = EXIT_FAILURE; + } + pthread_mutex_unlock(info->lock); + close(fd); + + pthread_exit((void *)ret); +} + + +/* + *---------------------------------------------------------------------------- + * + * addBlock -- + * + * Adds a block on the specified filename. + * + * Results: + * TRUE on success, FALSE on failure. + * + * Side effects: + * Future open(2)s on the file will block until delBlock() is called for + * that file. + * + *---------------------------------------------------------------------------- + */ + +static Bool +addBlock(int fd, // IN: fd of control device + char const *filename) // IN: filename to add block for +{ + Log("Blocking [%s]\n", filename); + return VMBLOCK_CONTROL(fd, VMBLOCK_ADD_FILEBLOCK, filename) == 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * delBlock -- + * + * Deletes a block on the specified filename. + * + * Results: + * TRUE on success, FALSE on failure. + * + * Side effects: + * Previous open(2)s that had blocked will now complete. + * + *---------------------------------------------------------------------------- + */ + +static Bool +delBlock(int fd, // IN: fd of control device + char const *filename) // IN: filename to delete block for +{ + Log("Unblocking [%s]\n", filename); + return VMBLOCK_CONTROL(fd, VMBLOCK_DEL_FILEBLOCK, filename) == 0; +} + + +/* + *---------------------------------------------------------------------------- + * + * listBlocks -- + * + * Tells the kernel module to list all existing blocks. + * + * Results: + * TRUE on success, FALSE on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static Bool +listBlocks(int fd) // IN: fd of control device +{ + Log("Listing blocks (check kernel log output)\n"); + return VMBLOCK_CONTROL(fd, VMBLOCK_LIST_FILEBLOCKS, NULL) == 0; +} + + +#ifdef VMBLOCK_PURGE_FILEBLOCKS +/* + *---------------------------------------------------------------------------- + * + * purgeBlocks -- + * + * Tells the kernel module to purge all existing blocks, regardless of + * who opened them. + * + * Results: + * TRUE on success, FALSE on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static Bool +purgeBlocks(int fd) // IN: fd of control device +{ + Log("Purging all blocks\n"); + return VMBLOCK_CONTROL(fd, VMBLOCK_PURGE_FILEBLOCKS, NULL) == 0; +} +#endif + + +/* + *---------------------------------------------------------------------------- + * + * getRand -- + * + * Retrieves the next random number within the range [0, max]. + * + * Results: + * A random number. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------------- + */ + +static unsigned int +getRand(unsigned int max) // IN: max value returnable +{ + return random() % max; +} + + +/* + *---------------------------------------------------------------------------- + * + * sighandler -- + * + * Sets the programQuit flag when a signal is received. + * + * Results: + * None. + * + * Side effects: + * Program will quit. + * + *---------------------------------------------------------------------------- + */ + +static void +sighandler(int sig) +{ + programQuit = TRUE; +} diff --git a/open-vm-tools/toolbox/toolbox-cmd.c b/open-vm-tools/toolbox/toolbox-cmd.c index 33534bba5..d84dee8a2 100644 --- a/open-vm-tools/toolbox/toolbox-cmd.c +++ b/open-vm-tools/toolbox/toolbox-cmd.c @@ -328,7 +328,6 @@ StatHelp(const char *progName) // IN: The name of the program obtained from argv "Usage: %s stat \n\n" "Subcommands\n" " hosttime: print the host time\n" - " memory: print the virtual machine memory in MBs\n" " speed: print the CPU speed in MHz\n" "ESX guests only subcommands\n" " sessionid: print the current session id\n" @@ -487,9 +486,7 @@ static int StatCommand(char **argv, // IN: Command line arguments int argc) // IN: Length of command line arguments { - if (toolbox_strcmp(argv[optind], "memory") == 0) { - return Stat_MemorySize(); - } else if (toolbox_strcmp(argv[optind], "hosttime") == 0) { + if (toolbox_strcmp(argv[optind], "hosttime") == 0) { return Stat_HostTime(); } else if (toolbox_strcmp(argv[optind], "sessionid") == 0) { return Stat_GetSessionID(); @@ -732,7 +729,14 @@ main(int argc, // IN: length of command line arguments ToolboxUnknownEntityError(argv[0], "command", argv[optind]); retval = EX_USAGE; } else if (cmd->requireRoot && !System_IsUserAdmin()) { - fprintf(stderr, "%s: You must be root to perform %s operations", + fprintf(stderr, +#ifdef _WIN32 + "%s: Administrator permissions are needed to perform %s " + "operations. Use an administrator command prompt to " + "complete these tasks.", +#else + "%s: You must be root to perform %s operations", +#endif argv[0], cmd->command); retval = EX_NOPERM; } else if (cmd->requireArguments && ++optind >= argc) { diff --git a/open-vm-tools/toolbox/toolboxCmdInt.h b/open-vm-tools/toolbox/toolboxCmdInt.h index 901f2e5f2..1a8673c36 100644 --- a/open-vm-tools/toolbox/toolboxCmdInt.h +++ b/open-vm-tools/toolbox/toolboxCmdInt.h @@ -112,7 +112,6 @@ int Shrink_DoShrink(char*, int); * Stat commands */ -int Stat_MemorySize(void); int Stat_HostTime(void); int Stat_ProcessorSpeed(void); int Stat_GetSessionID(void); diff --git a/open-vm-tools/toolbox/toolboxInt.h b/open-vm-tools/toolbox/toolboxInt.h index ce0a94d08..56b0685d4 100644 --- a/open-vm-tools/toolbox/toolboxInt.h +++ b/open-vm-tools/toolbox/toolboxInt.h @@ -43,7 +43,7 @@ #define MAX_DEVICES 50 /* maximum number of devices we'll show */ #define SHRINK_DISABLED_ERR "Shrink disk is disabled for this virtual machine.\n\n" \ "Shrinking is disabled for linked clones, parents of " \ - "linked clones, \npre-allocated disks, snapshots, and " \ + "linked clones, \npre-allocated disks, snapshots, or due to " \ "other factors. \nSee the User's manual for more " \ "information.\n" #define SHRINK_FEATURE_ERR "The shrink feature is not available,\n\n" \ @@ -51,7 +51,7 @@ "because too many communication channels are open.\n\n If you are running " \ "an old version of a VMware product, you should consider upgrading.\n\n" \ "If too many communication channels are open, you should power off your " \ - "virtual machine and then power it back on\n." + "virtual machine and then power it back on.\n" #define SHRINK_CONFLICT_ERR "Error, The Toolbox believes disk shrinking is " \ "enabled while the host believes it is disabled.\n\n " \ "Please close and reopen the Toolbox to synchronize " \ diff --git a/open-vm-tools/toolbox/toolboxShrink.c b/open-vm-tools/toolbox/toolboxShrink.c index 845e4c65e..46afeea39 100644 --- a/open-vm-tools/toolbox/toolboxShrink.c +++ b/open-vm-tools/toolbox/toolboxShrink.c @@ -71,9 +71,7 @@ Shrink_Create(GtkWidget *mainWnd) GtkWidget *viewport; GtkWidget *ebox; - int i; - WiperPartition_List *plist; - WiperPartition *partkb; + WiperPartition_List plist; gchar *items; int newrow; @@ -155,19 +153,25 @@ Shrink_Create(GtkWidget *mainWnd) gtk_clist_set_selection_mode(GTK_CLIST(shrinkList), GTK_SELECTION_MULTIPLE); Wiper_Init(NULL); - plist = WiperPartition_Open(); - if (plist != NULL) { - for (i=0; i < plist->size; i++) { - if (strlen(plist->partitions[i].comment) == 0) { - partkb = (WiperPartition *)malloc(sizeof (WiperPartition)); - memcpy(partkb, &(plist->partitions[i]), sizeof (WiperPartition)); - items = partkb->mountPoint; + if (WiperPartition_Open(&plist)) { + DblLnkLst_Links *curr, *next; + + DblLnkLst_ForEachSafe(curr, next, &plist.link) { + WiperPartition *part = DblLnkLst_Container(curr, WiperPartition, link); + + if (part->type != PARTITION_UNSUPPORTED) { + /* + * Detach the element we are interested in so it is not + * destroyed when we call WiperPartition_Close. + */ + DblLnkLst_Unlink1(&part->link); + items = part->mountPoint; newrow = gtk_clist_append(GTK_CLIST(shrinkList), &items); - gtk_clist_set_row_data(GTK_CLIST(shrinkList), newrow, - partkb); + gtk_clist_set_row_data_full(GTK_CLIST(shrinkList), newrow, + part, (GDestroyNotify)WiperSinglePartition_Close); } } - WiperPartition_Close(plist); + WiperPartition_Close(&plist); } } else { label = gtk_label_new(SHRINK_DISABLED_ERR); @@ -184,7 +188,6 @@ Shrink_Create(GtkWidget *mainWnd) gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_LEFT); gtk_misc_set_alignment(GTK_MISC(label), 0, 0); - } } @@ -229,8 +232,7 @@ Shrink_OnShrinkClicked(GtkButton *btn, // IN: unused } do { rnum = GPOINTER_TO_UINT(slist->data); - part = (WiperPartition *)(gtk_clist_get_row_data(GTK_CLIST(shrinkList), - rnum)); + part = gtk_clist_get_row_data(GTK_CLIST(shrinkList), rnum); if (Shrink_DoWipe(part, mainWnd)) { disks_to_shrink++; slist = slist->next; @@ -244,7 +246,7 @@ Shrink_OnShrinkClicked(GtkButton *btn, // IN: unused if (ToolsMain_YesNoBox("Shrink Disk", "Do you want to shrink the disk(s)?\n")) { if (GuestApp_DiskShrink()) { - ToolsMain_MsgBox("Information", "The shrink process is complete."); + ToolsMain_MsgBox("Information", "The shrink process has finished."); } gtk_clist_unselect_all(GTK_CLIST(shrinkList)); } diff --git a/open-vm-tools/toolbox/toolboxcmd-scripts.c b/open-vm-tools/toolbox/toolboxcmd-scripts.c index ccf8bf015..24e741a67 100644 --- a/open-vm-tools/toolbox/toolboxcmd-scripts.c +++ b/open-vm-tools/toolbox/toolboxcmd-scripts.c @@ -363,7 +363,7 @@ Script_Set(const char *apm, // IN: APM name GError *err = NULL; if (!File_Exists(path)) { - fprintf(stderr, "%s doesn't exists\n", path); + fprintf(stderr, "%s doesn't exist\n", path); return EX_OSFILE; } diff --git a/open-vm-tools/toolbox/toolboxcmd-shrink.c b/open-vm-tools/toolbox/toolboxcmd-shrink.c index d06dcb5f4..33e4f643b 100644 --- a/open-vm-tools/toolbox/toolboxcmd-shrink.c +++ b/open-vm-tools/toolbox/toolboxcmd-shrink.c @@ -37,8 +37,8 @@ static void ShrinkWiperDestroy(int signal); #endif -static WiperPartition_List * ShrinkGetMountPoints(void); -static WiperPartition * ShrinkGetPartition(char *mountPoint, int quiet_flag); +static Bool ShrinkGetMountPoints(WiperPartition_List *); +static WiperPartition * ShrinkGetPartition(char *mountPoint); static Wiper_State *wiper = NULL; @@ -59,19 +59,24 @@ static Wiper_State *wiper = NULL; */ int -Shrink_List(void) // IN: Verbosity flag. +Shrink_List(void) { - int i; - WiperPartition_List *plist = ShrinkGetMountPoints(); - if (plist == NULL) { + WiperPartition_List plist; + DblLnkLst_Links *curr; + + if (!ShrinkGetMountPoints(&plist)) { return EX_TEMPFAIL; } - for (i = 0; i < plist->size; i++) { - if (strlen(plist->partitions[i].comment) == 0) { - printf("%s\n", plist->partitions[i].mountPoint); + + DblLnkLst_ForEach(curr, &plist.link) { + WiperPartition *p = DblLnkLst_Container(curr, WiperPartition, link); + if (p->type != PARTITION_UNSUPPORTED) { + printf("%s\n", p->mountPoint); } } - WiperPartition_Close(plist); + + WiperPartition_Close(&plist); + return EXIT_SUCCESS; } @@ -93,25 +98,32 @@ Shrink_List(void) // IN: Verbosity flag. */ static WiperPartition* -ShrinkGetPartition(char *mountPoint, // IN: mount point - int quiet_flag) // IN: Verbosity flag +ShrinkGetPartition(char *mountPoint) { - int i; - WiperPartition *part; - WiperPartition_List *plist = ShrinkGetMountPoints(); - if (!plist) { + WiperPartition_List plist; + WiperPartition *p, *part = NULL; + DblLnkLst_Links *curr; + + if (!ShrinkGetMountPoints(&plist)) { return NULL; } - part = (WiperPartition *) malloc(sizeof *part); - for (i = 0; i < plist->size; i++) { - if (toolbox_strcmp(plist->partitions[i].mountPoint, mountPoint) == 0) { - memcpy(part, &plist->partitions[i], sizeof *part); - WiperPartition_Close(plist); - return part; + + DblLnkLst_ForEach(curr, &plist.link) { + p = DblLnkLst_Container(curr, WiperPartition, link); + if (toolbox_strcmp(p->mountPoint, mountPoint) == 0) { + part = p; + /* + * Detach the element we are interested in so it is not + * destroyed when we call WiperPartition_Close. + */ + DblLnkLst_Unlink1(&part->link); + break; } } - WiperPartition_Close(plist); - return NULL; + + WiperPartition_Close(&plist); + + return part; } @@ -131,19 +143,19 @@ ShrinkGetPartition(char *mountPoint, // IN: mount point *----------------------------------------------------------------------------- */ -static WiperPartition_List* -ShrinkGetMountPoints(void) // IN: Verbosity flag +static Bool +ShrinkGetMountPoints(WiperPartition_List *pl) // OUT: Known mount points { - if (GuestApp_IsDiskShrinkCapable()) { - if (GuestApp_IsDiskShrinkEnabled()) { - return WiperPartition_Open(); - } else { - fprintf(stderr,SHRINK_DISABLED_ERR); - } - } else { + if (!GuestApp_IsDiskShrinkCapable()) { fprintf(stderr, SHRINK_FEATURE_ERR); + } else if (!GuestApp_IsDiskShrinkEnabled()) { + fprintf(stderr, SHRINK_DISABLED_ERR); + } else if (!WiperPartition_Open(pl)) { + fprintf(stderr, "Unable to collect partition data.\n"); + } else { + return TRUE; } - return NULL; + return FALSE; } @@ -175,18 +187,22 @@ Shrink_DoShrink(char *mountPoint, // IN: mount point int progress = 0; unsigned char *err; WiperPartition *part; + int rc; + #ifndef _WIN32 signal(SIGINT, ShrinkWiperDestroy); #endif - part = ShrinkGetPartition(mountPoint, quiet_flag); + + part = ShrinkGetPartition(mountPoint); if (part == NULL) { fprintf(stderr, "Unable to find partition %s\n", mountPoint); return EX_OSFILE; } - if (strlen(part->comment) != 0) { + if (part->type == PARTITION_UNSUPPORTED) { fprintf(stderr, "Partition %s is not shrinkable\n", part->mountPoint); - return EX_UNAVAILABLE; + rc = EX_UNAVAILABLE; + goto out; } /* @@ -196,59 +212,57 @@ Shrink_DoShrink(char *mountPoint, // IN: mount point */ if (!GuestApp_IsDiskShrinkEnabled()) { fprintf(stderr, SHRINK_CONFLICT_ERR); - free(part); - return EX_TEMPFAIL; + rc = EX_TEMPFAIL; + goto out; } - wiper = Wiper_Start (part, MAX_WIPER_FILE_SIZE); + wiper = Wiper_Start(part, MAX_WIPER_FILE_SIZE); + while (progress < 100 && wiper != NULL) { err = Wiper_Next(&wiper, &progress); if (strlen(err) > 0) { if (strcmp(err, "error.create") == 0) { fprintf(stderr, "Error, Unable to create wiper file\n"); - free(part); - return EX_TEMPFAIL; - } - else { + } else { fprintf(stderr, "Error, %s", err); - free(part); - return EX_TEMPFAIL; } - free(wiper); - wiper = NULL; + + rc = EX_TEMPFAIL; } + if (!quiet_flag) { printf("\rProgress: %d [", progress); for (i = 0; i <= progress / 10; i++) { - printf("="); + putchar('='); } - printf(">"); - for (; i <= 100 / 10; i++) { - printf(" "); - } - printf("]"); + printf(">%*c", 10 - i + 1, ']'); + fflush(stdout); } } + if (progress >= 100) { char *result; size_t resultLen; + if (RpcOut_sendOne(&result, &resultLen, "disk.shrink")) { if (!quiet_flag) { printf("\nDisk shrinking complete\n"); } - wiper = NULL; - free(part); - return EXIT_SUCCESS; - } - if (!quiet_flag) { - fprintf(stderr, "%s\n", result); + rc = EXIT_SUCCESS; + goto out; } - wiper = NULL; - free(part); + + fprintf(stderr, "%s\n", result); } fprintf(stderr, "Shrinking not completed\n"); - return EX_TEMPFAIL; + rc = EX_TEMPFAIL; + +out: + WiperSinglePartition_Close(part); + free(wiper); + wiper = NULL; + return rc; } diff --git a/open-vm-tools/toolbox/toolboxcmd-stat.c b/open-vm-tools/toolbox/toolboxcmd-stat.c index dcf9fd319..08614f13a 100644 --- a/open-vm-tools/toolbox/toolboxcmd-stat.c +++ b/open-vm-tools/toolbox/toolboxcmd-stat.c @@ -105,40 +105,6 @@ Stat_ProcessorSpeed(void) } -/* - *----------------------------------------------------------------------------- - * - * Stat_MemorySize -- - * - * Gets the virtual machine's memory in MBs. - * - * Results: - * EXIT_SUCCESS on success. - * EX_TEMPFAIL on failure. - * - * Side effects: - * None. - * - *----------------------------------------------------------------------------- - */ - -int -Stat_MemorySize(void) -{ - uint32 memsize; - Backdoor_proto bp; - bp.in.cx.halfs.low = BDOOR_CMD_GETMEMSIZE; - Backdoor(&bp); - memsize = bp.out.ax.word; - if (memsize < 0) { - fprintf(stderr, "Unable to get memory size\n"); - return EX_TEMPFAIL; - } - printf("%u MB\n", memsize); - return EXIT_SUCCESS; -} - - /* *----------------------------------------------------------------------------- * diff --git a/open-vm-tools/vmware-user/Makefile.am b/open-vm-tools/vmware-user/Makefile.am index 9e6a8b4f3..443cb3ef8 100644 --- a/open-vm-tools/vmware-user/Makefile.am +++ b/open-vm-tools/vmware-user/Makefile.am @@ -63,6 +63,7 @@ else endif vmware_user_LDADD += ../lib/user/libUser.la vmware_user_LDADD += ../lib/vixTools/libVixTools.la +vmware_user_LDADD += ../lib/hgfsHelper/libHgfsHelper.la vmware_user_LDADD += ../lib/vmCheck/libVmCheck.la vmware_user_LDADD += ../lib/vmSignal/libVmSignal.la vmware_user_LDADD += ../lib/wiper/libWiper.la @@ -98,7 +99,8 @@ endif vmware_user_LDADD += -lcrypt vmware_user_LDADD += -lstdc++ if LINUX -vmware_user_LDADD += -lgcc_s + vmware_user_LDADD += -lgcc_s + vmware_user_LDADD += ../lib/slashProc/libSlashProc.la endif vmware_user_LDADD += @GTK_LIBS@ if HAVE_GTKMM diff --git a/open-vm-tools/vmware-user/copyPasteUI.cpp b/open-vm-tools/vmware-user/copyPasteUI.cpp index 16d6ec4d9..e6f3bbd50 100644 --- a/open-vm-tools/vmware-user/copyPasteUI.cpp +++ b/open-vm-tools/vmware-user/copyPasteUI.cpp @@ -582,11 +582,12 @@ CopyPasteUI::LocalPrimTimestampCB(const Gtk::SelectionData& sd) // IN } Glib::RefPtr refClipboard; + bool flipped = false; again: + bool validDataInClip = false; refClipboard = Gtk::Clipboard::get(mGHSelection); - Debug("%s: trying %s selection, trying again\n", - __FUNCTION__, + Debug("%s: trying %s selection.\n", __FUNCTION__, mGHSelection == GDK_SELECTION_PRIMARY ? "Primary" : "Clip"); CPClipboard_Clear(&mClipboard); @@ -656,9 +657,8 @@ again: bufSize <= (int)CPCLIPITEM_MAX_SIZE_V3 && CPClipboard_SetItem(&mClipboard, CPFORMAT_RTF, (const void *)sdata.get_data(), bufSize + 1)) { - mCP.SetRemoteClipboard(&mClipboard); + validDataInClip = true; Debug("%s: Got RTF\n", __FUNCTION__); - return; } else { Debug("%s: Failed to get RTF size %d max %d\n", __FUNCTION__, (int) bufSize, (int)CPCLIPITEM_MAX_SIZE_V3); @@ -674,26 +674,30 @@ again: bufSize <= (int)CPCLIPITEM_MAX_SIZE_V3 && CPClipboard_SetItem(&mClipboard, CPFORMAT_TEXT, (const void *)str.data(), bufSize + 1)) { - mCP.SetRemoteClipboard(&mClipboard); + validDataInClip = true; Debug("%s: Got TEXT: %"FMTSZ"u\n", __FUNCTION__, bufSize); - return; - } else if (mClipTime == mPrimTime && mClipTime) { - /* - * With 'cut' operation OpenOffice will put data into clipboard but - * set the same timestamp for both clipboard and primary selection. - * If primary timestamp is same as clipboard timestamp, we should try - * clipboard again if primary selection is empty. For details, please - * refer to bug 300780. - */ - mClipTime = 0; - mPrimTime = 0; - mGHSelection = GDK_SELECTION_CLIPBOARD; - Debug("%s: trying again with clip\n", __FUNCTION__); - goto again; } else { Debug("%s: Failed to get TEXT\n", __FUNCTION__); } } + + if (validDataInClip) { + /* + * RTF or text data (or both) in the clipboard. + */ + mCP.SetRemoteClipboard(&mClipboard); + } else if (!flipped) { + /* + * If we get here, we got nothing (no image, URI, text) so + * try the other selection. + */ + Debug("%s: got nothing for this selection, try the other.\n", + __FUNCTION__); + mGHSelection = mGHSelection == GDK_SELECTION_PRIMARY ? + GDK_SELECTION_CLIPBOARD : GDK_SELECTION_PRIMARY; + flipped = true; + goto again; + } } diff --git a/open-vm-tools/vmware-user/stringxx/string.cc b/open-vm-tools/vmware-user/stringxx/string.cc index 3816fe9e7..6d2b76d5c 100644 --- a/open-vm-tools/vmware-user/stringxx/string.cc +++ b/open-vm-tools/vmware-user/stringxx/string.cc @@ -62,7 +62,8 @@ const string::size_type string::npos = Glib::ustring::npos; string::string() : mUstr(), - mUtf16Cache(NULL) + mUtf16Cache(NULL), + mUtf16Length(npos) { } @@ -85,7 +86,8 @@ string::string() string::string(ConstUnicode s) // IN : mUstr(), - mUtf16Cache(NULL) + mUtf16Cache(NULL), + mUtf16Length(npos) { ASSERT(s); mUstr = Unicode_GetUTF8(s); @@ -118,7 +120,8 @@ string::string(ConstUnicode s) // IN string::string(const ubstr_t &s) // IN : mUstr(), - mUtf16Cache(NULL) + mUtf16Cache(NULL), + mUtf16Length(npos) { // If the input is empty, then there's nothing to do. if (s.length() == 0) { @@ -153,7 +156,8 @@ string::string(const ubstr_t &s) // IN string::string(const _bstr_t &s) // IN : mUstr(), - mUtf16Cache(NULL) + mUtf16Cache(NULL), + mUtf16Length(npos) { // If the input is empty, then there's nothing to do. if (s.length() == 0) { @@ -194,7 +198,8 @@ string::string(const _bstr_t &s) // IN string::string(const utf16string &s) // IN : mUstr(), - mUtf16Cache(NULL) + mUtf16Cache(NULL), + mUtf16Length(npos) { // If the input is empty, then there's nothing to do. if (s.empty()) { @@ -224,7 +229,8 @@ string::string(const utf16string &s) // IN string::string(const utf16_t *s) // IN : mUstr(), - mUtf16Cache(NULL) + mUtf16Cache(NULL), + mUtf16Length(npos) { ASSERT(s != NULL); @@ -267,7 +273,8 @@ string::string(const utf16_t *s) // IN string::string(const char *s, // IN StringEncoding encoding) // IN : mUstr(), - mUtf16Cache(NULL) + mUtf16Cache(NULL), + mUtf16Length(npos) { ASSERT(s != NULL); @@ -309,7 +316,8 @@ string::string(const char *s, // IN string::string(const Glib::ustring &s) // IN : mUstr(s.c_str()), - mUtf16Cache(NULL) + mUtf16Cache(NULL), + mUtf16Length(npos) { ASSERT(Validate(s)); } @@ -339,7 +347,8 @@ string::string(const Glib::ustring &s) // IN string::string(const string &s) // IN : mUstr(s.mUstr.c_str()), - mUtf16Cache(NULL) + mUtf16Cache(NULL), + mUtf16Length(npos) { } @@ -494,6 +503,7 @@ string::swap(string &s) // IN/OUT { mUstr.swap(s.mUstr); std::swap(mUtf16Cache, s.mUtf16Cache); + std::swap(mUtf16Length, s.mUtf16Length); } @@ -641,6 +651,33 @@ string::size() } +/* + *----------------------------------------------------------------------------- + * + * utf::string::w_size -- + * + * Results: + * Returns the length of this string, in UTF-16 code units, + * excluding NUL. + * + * Side effects: + * None + * + *----------------------------------------------------------------------------- + */ + +string::size_type +string::w_size() + const +{ + if (mUtf16Length == npos) { + mUtf16Length = Unicode_UTF16Strlen(GetUtf16Cache()); + } + + return mUtf16Length; +} + + /* *----------------------------------------------------------------------------- * @@ -1739,6 +1776,7 @@ string::InvalidateCache() { free(mUtf16Cache); mUtf16Cache = NULL; + mUtf16Length = npos; } @@ -2185,7 +2223,7 @@ void CreateWritableBuffer(const string& s, // IN: std::vector& buf) // OUT: A copy of the string, as UTF-16. { - CopyArray(s.w_str(), Unicode_UTF16Strlen(s.w_str()) + 1, buf); + CopyArray(s.w_str(), s.w_size() + 1, buf); } diff --git a/open-vm-tools/vmware-user/stringxx/string.hh b/open-vm-tools/vmware-user/stringxx/string.hh index 442e78602..cfc507e7a 100644 --- a/open-vm-tools/vmware-user/stringxx/string.hh +++ b/open-vm-tools/vmware-user/stringxx/string.hh @@ -129,6 +129,7 @@ public: void resize(size_type n, value_type c = '\0'); bool empty() const; size_type size() const; + size_type w_size() const; size_type length() const; size_type bytes() const; string foldCase() const; @@ -219,6 +220,12 @@ private: // Cached representations. mutable utf16_t *mUtf16Cache; + mutable size_type mUtf16Length; + + /* + * All added members need to be initialized in all constructors and need + * to be handled in swap(). + */ }; // Helper operators