From: Lucian Petrut Date: Tue, 5 May 2020 10:20:46 +0000 (+0000) Subject: common: move Windows files to a separate folder X-Git-Tag: v16.1.0~543^2~8 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=00a5cd1d43e485e9ced6789c041498f5785e58b4;p=ceph.git common: move Windows files to a separate folder We ended up with quite a few files having the "_win32" suffix. It's probably better if we move them to a separate folder and drop the suffix. Signed-off-by: Lucian Petrut --- diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index efd1b24440dd6..e9a732ba9161f 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -8,7 +8,7 @@ add_library(common_prioritycache_obj OBJECT PriorityCache.cc) if(WIN32) - add_library(dlfcn_win32 STATIC dlfcn_win32.cc win32_errno.cc) + add_library(dlfcn_win32 STATIC win32/dlfcn.cc win32/errno.cc) endif() set(common_srcs @@ -105,12 +105,12 @@ set(common_srcs if(WIN32) list(APPEND common_srcs - blkdev_win32.cc - dns_resolve_win32.cc - SubProcess_win32.cc - ifaddrs_win32.c - registry_win32.cc - service_win32.cc) + win32/blkdev.cc + win32/dns_resolve.cc + win32/ifaddrs.cc + win32/registry.cc + win32/service.cc + win32/SubProcess.cc) else() list(APPEND common_srcs blkdev.cc @@ -138,7 +138,7 @@ elseif(SUN) elseif(AIX) list(APPEND common_srcs aix_errno.cc) elseif(WIN32) - list(APPEND common_srcs win32_errno.cc) + list(APPEND common_srcs win32/errno.cc) endif() if(WITH_EVENTTRACE) diff --git a/src/common/SubProcess_win32.cc b/src/common/SubProcess_win32.cc deleted file mode 100644 index 0e4d13dd71a60..0000000000000 --- a/src/common/SubProcess_win32.cc +++ /dev/null @@ -1,293 +0,0 @@ -#include "SubProcess.h" - -#include -#include -#include -#include -#include - -#include "common/errno.h" -#include "include/ceph_assert.h" -#include "include/compat.h" - -SubProcess::SubProcess(const char *cmd_, std_fd_op stdin_op_, std_fd_op stdout_op_, std_fd_op stderr_op_) : - cmd(cmd_), - cmd_args(), - stdin_op(stdin_op_), - stdout_op(stdout_op_), - stderr_op(stderr_op_), - stdin_pipe_out_fd(-1), - stdout_pipe_in_fd(-1), - stderr_pipe_in_fd(-1), - pid(0), - errstr() { -} - -SubProcess::~SubProcess() { - ceph_assert(!is_spawned()); - ceph_assert(stdin_pipe_out_fd == -1); - ceph_assert(stdout_pipe_in_fd == -1); - ceph_assert(stderr_pipe_in_fd == -1); -} - -void SubProcess::add_cmd_args(const char *arg, ...) { - ceph_assert(!is_spawned()); - - va_list ap; - va_start(ap, arg); - const char *p = arg; - do { - add_cmd_arg(p); - p = va_arg(ap, const char*); - } while (p != NULL); - va_end(ap); -} - -void SubProcess::add_cmd_arg(const char *arg) { - ceph_assert(!is_spawned()); - - cmd_args.push_back(arg); -} - -int SubProcess::get_stdin() const { - ceph_assert(is_spawned()); - ceph_assert(stdin_op == PIPE); - - return stdin_pipe_out_fd; -} - -int SubProcess::get_stdout() const { - ceph_assert(is_spawned()); - ceph_assert(stdout_op == PIPE); - - return stdout_pipe_in_fd; -} - -int SubProcess::get_stderr() const { - ceph_assert(is_spawned()); - ceph_assert(stderr_op == PIPE); - - return stderr_pipe_in_fd; -} - -void SubProcess::close(int &fd) { - if (fd == -1) - return; - - ::close(fd); - fd = -1; -} - -void SubProcess::close_stdin() { - ceph_assert(is_spawned()); - ceph_assert(stdin_op == PIPE); - - close(stdin_pipe_out_fd); -} - -void SubProcess::close_stdout() { - ceph_assert(is_spawned()); - ceph_assert(stdout_op == PIPE); - - close(stdout_pipe_in_fd); -} - -void SubProcess::close_stderr() { - ceph_assert(is_spawned()); - ceph_assert(stderr_op == PIPE); - - close(stderr_pipe_in_fd); -} - -const std::string SubProcess::err() const { - return errstr.str(); -} - -SubProcessTimed::SubProcessTimed(const char *cmd, std_fd_op stdin_op, - std_fd_op stdout_op, std_fd_op stderr_op, - int timeout_, int sigkill_) : - SubProcess(cmd, stdin_op, stdout_op, stderr_op), - timeout(timeout_), - sigkill(sigkill_) { -} - -static bool timedout = false; -void timeout_sighandler(int sig) { - timedout = true; -} - -void SubProcess::close_h(HANDLE &handle) { - if (handle == INVALID_HANDLE_VALUE) - return; - - CloseHandle(handle); - handle = INVALID_HANDLE_VALUE; -} - -int SubProcess::join() { - ceph_assert(is_spawned()); - - close(stdin_pipe_out_fd); - close(stdout_pipe_in_fd); - close(stderr_pipe_in_fd); - - DWORD status = 0; - - if (WaitForSingleObject(proc_handle, INFINITE) != WAIT_FAILED) { - if (!GetExitCodeProcess(proc_handle, &status)) { - errstr << cmd << ": Could not get exit code: " << pid - << ". Error code: " << GetLastError(); - } else if (status) { - errstr << cmd << ": exit status: " << status; - } - } else { - errstr << cmd << ": Waiting for child process failed: " << pid - << ". Error code: " << GetLastError(); - } - - close_h(proc_handle); - pid = 0; - return status; -} - -void SubProcess::kill(int signo) const { - ceph_assert(is_spawned()); - ceph_assert(TerminateProcess(proc_handle, 128 + SIGTERM)); -} - -int SubProcess::spawn() { - std::ostringstream cmdline; - cmdline << cmd; - for (auto& arg : cmd_args) { - cmdline << " " << std::quoted(arg); - } - - STARTUPINFO si = {0}; - PROCESS_INFORMATION pi = {0}; - SECURITY_ATTRIBUTES sa = {0}; - - sa.nLength = sizeof(SECURITY_ATTRIBUTES); - sa.bInheritHandle = TRUE; - sa.lpSecurityDescriptor = NULL; - - HANDLE stdin_r = INVALID_HANDLE_VALUE, stdin_w = INVALID_HANDLE_VALUE, - stdout_r = INVALID_HANDLE_VALUE, stdout_w = INVALID_HANDLE_VALUE, - stderr_r = INVALID_HANDLE_VALUE, stderr_w = INVALID_HANDLE_VALUE; - - if ((stdin_op == PIPE && !CreatePipe(&stdin_r, &stdin_w, &sa, 0)) || - (stdout_op == PIPE && !CreatePipe(&stdout_r, &stdout_w, &sa, 0)) || - (stderr_op == PIPE && !CreatePipe(&stderr_r, &stderr_w, &sa, 0))) { - errstr << cmd << ": CreatePipe failed: " << GetLastError(); - return -1; - } - - // The following handles will be used by the parent process and - // must be marked as non-inheritable. - if ((stdin_op == PIPE && !SetHandleInformation(stdin_w, HANDLE_FLAG_INHERIT, 0)) || - (stdout_op == PIPE && !SetHandleInformation(stdout_r, HANDLE_FLAG_INHERIT, 0)) || - (stderr_op == PIPE && !SetHandleInformation(stderr_r, HANDLE_FLAG_INHERIT, 0))) { - errstr << cmd << ": SetHandleInformation failed: " - << GetLastError(); - goto fail; - } - - si.cb = sizeof(STARTUPINFO); - si.hStdInput = stdin_op == KEEP ? GetStdHandle(STD_INPUT_HANDLE) : stdin_r; - si.hStdOutput = stdout_op == KEEP ? GetStdHandle(STD_OUTPUT_HANDLE) : stdout_w; - si.hStdError = stderr_op == KEEP ? GetStdHandle(STD_ERROR_HANDLE) : stderr_w; - si.dwFlags |= STARTF_USESTDHANDLES; - - stdin_pipe_out_fd = stdin_op == PIPE ? _open_osfhandle((intptr_t)stdin_w, 0) : -1; - stdout_pipe_in_fd = stdout_op == PIPE ? _open_osfhandle((intptr_t)stdout_r, _O_RDONLY) : - 1; - stderr_pipe_in_fd = stderr_op == PIPE ? _open_osfhandle((intptr_t)stderr_r, _O_RDONLY) : -1; - - if (stdin_op == PIPE && stdin_pipe_out_fd == -1 || - stdout_op == PIPE && stdout_pipe_in_fd == -1 || - stderr_op == PIPE && stderr_pipe_in_fd == -1) { - errstr << cmd << ": _open_osfhandle failed: " << GetLastError(); - goto fail; - } - - // We've transfered ownership from those handles. - stdin_w = stdout_r = stderr_r = INVALID_HANDLE_VALUE; - - if (!CreateProcess( - NULL, const_cast(cmdline.str().c_str()), - NULL, NULL, /* No special security attributes */ - 1, /* Inherit handles marked as inheritable */ - 0, /* No special flags */ - NULL, /* Use the same environment variables */ - NULL, /* use the same cwd */ - &si, &pi)) { - errstr << cmd << ": CreateProcess failed: " << GetLastError(); - goto fail; - } - - proc_handle = pi.hProcess; - pid = GetProcessId(proc_handle); - if (!pid) { - errstr << cmd << ": Could not get child process id."; - goto fail; - } - - // The following are used by the subprocess. - CloseHandle(stdin_r); - CloseHandle(stdout_w); - CloseHandle(stderr_w); - CloseHandle(pi.hThread); - return 0; - -fail: - // fd copies - close(stdin_pipe_out_fd); - close(stdout_pipe_in_fd); - close(stderr_pipe_in_fd); - - // the original handles - close_h(stdin_r); - close_h(stdin_w); - close_h(stdout_r); - close_h(stdout_w); - close_h(stderr_r); - close_h(stderr_w); - - // We may consider mapping some of the Windows errors. - return -1; -} - -void SubProcess::exec() { -} - -int SubProcessTimed::spawn() { - if (auto ret = SubProcess::spawn(); ret < 0) { - return ret; - } - - if (timeout > 0) { - waiter = std::thread([&](){ - DWORD wait_status = WaitForSingleObject(proc_handle, timeout * 1000); - ceph_assert(wait_status != WAIT_FAILED); - if (wait_status == WAIT_TIMEOUT) { - // 128 + sigkill is just the return code, which is expected by - // the unit tests and possibly by other code. We can't pick a - // termination signal unless we use window events. - ceph_assert(TerminateProcess(proc_handle, 128 + sigkill)); - timedout = 1; - } - }); - } - return 0; -} - -int SubProcessTimed::join() { - ceph_assert(is_spawned()); - - if (waiter.joinable()) { - waiter.join(); - } - - return SubProcess::join();; -} - -void SubProcessTimed::exec() { -} diff --git a/src/common/blkdev_win32.cc b/src/common/blkdev_win32.cc deleted file mode 100644 index c3e28e343ff83..0000000000000 --- a/src/common/blkdev_win32.cc +++ /dev/null @@ -1,137 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2020 SUSE LINUX GmbH - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#include -#include "blkdev.h" - -int get_device_by_path(const char *path, char* partition, char* device, - size_t max) -{ - return -EOPNOTSUPP; -} - - -BlkDev::BlkDev(int f) - : fd(f) -{} - -BlkDev::BlkDev(const std::string& devname) - : devname(devname) -{} - -int BlkDev::get_devid(dev_t *id) const -{ - return -EOPNOTSUPP; -} - -const char *BlkDev::sysfsdir() const { - assert(false); // Should never be called on Windows - return ""; -} - -int BlkDev::dev(char *dev, size_t max) const -{ - return -EOPNOTSUPP; -} - -int BlkDev::get_size(int64_t *psize) const -{ - return -EOPNOTSUPP; -} - -bool BlkDev::support_discard() const -{ - return false; -} - -int BlkDev::discard(int64_t offset, int64_t len) const -{ - return -EOPNOTSUPP; -} - -bool BlkDev::is_rotational() const -{ - return false; -} - -int BlkDev::model(char *model, size_t max) const -{ - return -EOPNOTSUPP; -} - -int BlkDev::serial(char *serial, size_t max) const -{ - return -EOPNOTSUPP; -} - -int BlkDev::partition(char *partition, size_t max) const -{ - return -EOPNOTSUPP; -} - -int BlkDev::wholedisk(char *wd, size_t max) const -{ - return -EOPNOTSUPP; -} - -void get_dm_parents(const std::string& dev, std::set *ls) -{ -} - -void get_raw_devices(const std::string& in, - std::set *ls) -{ -} - -int get_vdo_stats_handle(const char *devname, std::string *vdo_name) -{ - return -1; -} - -int64_t get_vdo_stat(int fd, const char *property) -{ - return 0; -} - -bool get_vdo_utilization(int fd, uint64_t *total, uint64_t *avail) -{ - return false; -} - -std::string get_device_id(const std::string& devname, - std::string *err) -{ - if (err) { - *err = "not implemented"; - } - return std::string(); -} - -int block_device_run_smartctl(const char *device, int timeout, - std::string *result) -{ - return -EOPNOTSUPP; -} - -int block_device_get_metrics(const std::string& devname, int timeout, - json_spirit::mValue *result) -{ - return -EOPNOTSUPP; -} - -int block_device_run_nvme(const char *device, const char *vendor, int timeout, - std::string *result) -{ - return -EOPNOTSUPP; -} diff --git a/src/common/dlfcn_win32.cc b/src/common/dlfcn_win32.cc deleted file mode 100644 index 329d14677bd9d..0000000000000 --- a/src/common/dlfcn_win32.cc +++ /dev/null @@ -1,38 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2020 SUSE LINUX GmbH - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#include -#include - -#include "common/errno.h" -#include "include/dlfcn_compat.h" - - -void* dlopen(const char *filename, int flags) { - return LoadLibrary(filename); -} - -int dlclose(void* handle) { - //FreeLibrary returns 0 on error, as opposed to dlclose. - return !FreeLibrary(handle); -} - -void* dlsym(void* handle, const char* symbol) { - return (void*)GetProcAddress(handle, symbol); -} - -dl_errmsg_t dlerror() { - return win32_lasterror_str(); -} - diff --git a/src/common/dns_resolve_win32.cc b/src/common/dns_resolve_win32.cc deleted file mode 100644 index b7a888b30ebe1..0000000000000 --- a/src/common/dns_resolve_win32.cc +++ /dev/null @@ -1,65 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2019 SUSE LINUX GmbH - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#include "include/scope_guard.h" -#include "dns_resolve.h" -#include "common/debug.h" - -#define dout_subsys ceph_subsys_ - - -namespace ceph { - -int ResolvHWrapper::res_query(const char *hostname, int cls, - int type, u_char *buf, int bufsz) { - return -1; -} - -int ResolvHWrapper::res_search(const char *hostname, int cls, - int type, u_char *buf, int bufsz) { - return -1; -} - -DNSResolver::~DNSResolver() -{ - delete resolv_h; -} - -int DNSResolver::resolve_cname(CephContext *cct, const string& hostname, - string *cname, bool *found) -{ - return -ENOTSUP; -} - -int DNSResolver::resolve_ip_addr(CephContext *cct, const string& hostname, - entity_addr_t *addr) -{ - return -ENOTSUP; -} - -int DNSResolver::resolve_srv_hosts(CephContext *cct, const string& service_name, - const SRV_Protocol trans_protocol, - map *srv_hosts) -{ - return this->resolve_srv_hosts(cct, service_name, trans_protocol, "", srv_hosts); -} - -int DNSResolver::resolve_srv_hosts(CephContext *cct, const string& service_name, - const SRV_Protocol trans_protocol, const string& domain, - map *srv_hosts) -{ - return -ENOTSUP; -} - -} diff --git a/src/common/ifaddrs_win32.cc b/src/common/ifaddrs_win32.cc deleted file mode 100644 index d7de4a5ff8ae2..0000000000000 --- a/src/common/ifaddrs_win32.cc +++ /dev/null @@ -1,109 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include - -#include "include/compat.h" - -int getifaddrs(struct ifaddrs **ifap) -{ - int ret = 0; - - DWORD size, res = 0; - res = GetAdaptersAddresses( - AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, - NULL, NULL, &size); - if (res != ERROR_BUFFER_OVERFLOW) { - errno = ENOMEM; - return -1; - } - - PIP_ADAPTER_ADDRESSES adapter_addrs = (PIP_ADAPTER_ADDRESSES)malloc(size); - res = GetAdaptersAddresses( - AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, - NULL, adapter_addrs, &size); - if (res != ERROR_SUCCESS) { - errno = ENOMEM; - return -1; - } - - struct ifaddrs *out_list_head = NULL; - struct ifaddrs *out_list_curr; - - for (PIP_ADAPTER_ADDRESSES curr_addrs = adapter_addrs; - curr_addrs != NULL; - curr_addrs = curr_addrs->Next) { - if (curr_addrs->OperStatus != 1) - continue; - - for (PIP_ADAPTER_UNICAST_ADDRESS unicast_addrs = curr_addrs->FirstUnicastAddress; - unicast_addrs != NULL; - unicast_addrs = unicast_addrs->Next) { - SOCKADDR* unicast_sockaddr = unicast_addrs->Address.lpSockaddr; - if (unicast_sockaddr->sa_family != AF_INET && - unicast_sockaddr->sa_family != AF_INET6) - continue; - out_list_curr = calloc(sizeof(*out_list_curr), 1); - if (!out_list_curr) { - errno = ENOMEM; - ret = -1; - goto out; - } - - out_list_curr->ifa_next = out_list_head; - out_list_head = out_list_curr; - - out_list_curr->ifa_flags = IFF_UP; - if (curr_addrs->IfType == IF_TYPE_SOFTWARE_LOOPBACK) - out_list_curr->ifa_flags |= IFF_LOOPBACK; - - out_list_curr->ifa_addr = (struct sockaddr *) &out_list_curr->in_addrs; - out_list_curr->ifa_netmask = (struct sockaddr *) &out_list_curr->in_netmasks; - out_list_curr->ifa_name = out_list_curr->ad_name; - - if (unicast_sockaddr->sa_family == AF_INET) { - ULONG subnet_mask = 0; - if (ConvertLengthToIpv4Mask(unicast_addrs->OnLinkPrefixLength, &subnet_mask)) { - errno = ENODATA; - ret = -1; - goto out; - } - struct sockaddr_in *addr4 = (struct sockaddr_in *) &out_list_curr->in_addrs; - struct sockaddr_in *netmask4 = (struct sockaddr_in *) &out_list_curr->in_netmasks; - netmask4->sin_family = unicast_sockaddr->sa_family; - addr4->sin_family = unicast_sockaddr->sa_family; - netmask4->sin_addr.S_un.S_addr = subnet_mask; - addr4->sin_addr = ((struct sockaddr_in*) unicast_sockaddr)->sin_addr; - } else { - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &out_list_curr->in_addrs; - (*addr6) = *(struct sockaddr_in6 *) unicast_sockaddr; - } - out_list_curr->speed = curr_addrs->TransmitLinkSpeed; - // TODO maybe use friendly name instead of adapter GUID - sprintf_s(out_list_curr->ad_name, - sizeof(out_list_curr->ad_name), - curr_addrs->AdapterName); - } - } - ret = 0; -out: - free(adapter_addrs); - if (ret && out_list_head) - free(out_list_head); - else if (ifap) - *ifap = out_list_head; - - return ret; -} - -void freeifaddrs(struct ifaddrs *ifa) -{ - while (ifa) { - struct ifaddrs *next = ifa->ifa_next; - free(ifa); - ifa = next; - } -} diff --git a/src/common/registry_win32.cc b/src/common/registry_win32.cc deleted file mode 100644 index eb809a40f79ce..0000000000000 --- a/src/common/registry_win32.cc +++ /dev/null @@ -1,155 +0,0 @@ -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2020 SUSE LINUX GmbH - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#define dout_context cct -#define dout_subsys ceph_subsys_ - -#include "common/debug.h" -#include "common/errno.h" -#include "common/registry_win32.h" - -RegistryKey::RegistryKey(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey, - bool create_value): cct(cct_) -{ - DWORD status = RegOpenKeyEx(hRootKey, strKey, 0, KEY_ALL_ACCESS, &hKey); - - if (status == ERROR_FILE_NOT_FOUND && create_value) - { - ldout(cct_, 10) << "Creating registry key: " << strKey << dendl; - status = RegCreateKeyEx( - hRootKey, strKey, 0, NULL, REG_OPTION_NON_VOLATILE, - KEY_ALL_ACCESS, NULL, &hKey, NULL); - } - - if (ERROR_SUCCESS != status) { - if (ERROR_FILE_NOT_FOUND == status) { - missingKey = true; - } else { - lderr(cct_) << "Error: " << win32_strerror(status) - << ". Could not open registry key: " - << strKey << dendl; - } - } -} - -RegistryKey::~RegistryKey() { - if (!hKey) - return; - - DWORD status = RegCloseKey(hKey); - if (ERROR_SUCCESS != status) { - derr << "Error: " << win32_strerror(status) - << ". Could not close registry key." << dendl; - } else { - hKey = NULL; - } -} - -int RegistryKey::remove(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey) -{ - DWORD status = RegDeleteKeyEx(hRootKey, strKey, KEY_WOW64_64KEY, 0); - - if (status == ERROR_FILE_NOT_FOUND) - { - ldout(cct_, 20) << "Registry key : " << strKey - << " does not exist." << dendl; - return 0; - } - - if (ERROR_SUCCESS != status) { - lderr(cct_) << "Error: " << win32_strerror(status) - << ". Could not delete registry key: " - << strKey << dendl; - return -EINVAL; - } - - return 0; -} - -int RegistryKey::flush() { - DWORD status = RegFlushKey(hKey); - if (ERROR_SUCCESS != status) { - derr << "Error: " << win32_strerror(status) - << ". Could not flush registry key." << dendl; - return -EINVAL; - } - - return 0; -} - -int RegistryKey::set(LPCTSTR lpValue, DWORD data) -{ - DWORD status = RegSetValueEx(hKey, lpValue, 0, REG_DWORD, - (LPBYTE)&data, sizeof(DWORD)); - if (ERROR_SUCCESS != status) { - derr << "Error: " << win32_strerror(status) - << ". Could not set registry value: " << (char*)lpValue << dendl; - return -EINVAL; - } - - return 0; -} - -int RegistryKey::set(LPCTSTR lpValue, std::string data) -{ - DWORD status = RegSetValueEx(hKey, lpValue, 0, REG_SZ, - (LPBYTE)data.c_str(), data.length()); - if (ERROR_SUCCESS != status) { - derr << "Error: " << win32_strerror(status) - << ". Could not set registry value: " - << (char*)lpValue << dendl; - return -EINVAL; - } - return 0; -} - -int RegistryKey::get(LPCTSTR lpValue, DWORD* value) -{ - DWORD data; - DWORD size = sizeof(data); - DWORD type = REG_DWORD; - DWORD status = RegQueryValueEx(hKey, lpValue, NULL, - &type, (LPBYTE)&data, &size); - if (ERROR_SUCCESS != status) { - derr << "Error: " << win32_strerror(status) - << ". Could not get registry value: " - << (char*)lpValue << dendl; - return -EINVAL; - } - *value = data; - - return 0; -} - -int RegistryKey::get(LPCTSTR lpValue, std::string& value) -{ - std::string data{""}; - DWORD size = 0; - DWORD type = REG_SZ; - DWORD status = RegQueryValueEx(hKey, lpValue, NULL, &type, - (LPBYTE)data.c_str(), &size); - if (ERROR_MORE_DATA == status) { - data.resize(size); - status = RegQueryValueEx(hKey, lpValue, NULL, &type, - (LPBYTE)data.c_str(), &size); - } - - if (ERROR_SUCCESS != status) { - derr << "Error: " << win32_strerror(status) - << ". Could not get registry value: " - << (char*)lpValue << dendl; - return -EINVAL; - } - value.assign(data.c_str()); - - return 0; -} diff --git a/src/common/registry_win32.h b/src/common/registry_win32.h deleted file mode 100644 index 974d662de2d98..0000000000000 --- a/src/common/registry_win32.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2019 SUSE LINUX GmbH - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#include "include/compat.h" -#include "common/ceph_context.h" - - -class RegistryKey { -public: - RegistryKey(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey, bool create_value); - ~RegistryKey(); - - static remove(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey); - - int flush(); - - int set(LPCTSTR lpValue, DWORD data); - int set(LPCTSTR lpValue, std::string data); - - int get(LPCTSTR lpValue, DWORD* value); - int get(LPCTSTR lpValue, std::string& value); - - HKEY hKey = NULL; - bool missingKey = false; - -private: - CephContext *cct; -}; diff --git a/src/common/service_win32.cc b/src/common/service_win32.cc deleted file mode 100644 index 6297531d3de33..0000000000000 --- a/src/common/service_win32.cc +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2019 SUSE LINUX GmbH - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#define dout_context cct -#define dout_subsys ceph_subsys_ - -#include "common/debug.h" -#include "common/errno.h" -#include "common/service_win32.h" - -// Initialize the singleton service instance. -ServiceBase *ServiceBase::s_service = NULL; - -ServiceBase::ServiceBase(CephContext *cct_): cct(cct_) -{ - status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; - status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; - status.dwCurrentState = SERVICE_START_PENDING; - status.dwWin32ExitCode = NO_ERROR; - status.dwCheckPoint = 0; - /* The estimated time required for the stop operation in ms. */ - status.dwWaitHint = 0; -} - -/* Register service action callbacks */ -int ServiceBase::initialize(ServiceBase *service) -{ - s_service = service; - - SERVICE_TABLE_ENTRY service_table[] = { - {"", (LPSERVICE_MAIN_FUNCTION)run}, - {NULL, NULL} - }; - - /* StartServiceCtrlDispatcher blocks until the service is stopped. */ - if (!StartServiceCtrlDispatcher(service_table)) { - int err = GetLastError(); - lderr(service->cct) << "StartServiceCtrlDispatcher error: " - << err << dendl; - return -EINVAL; - } - return 0; -} - -void WINAPI ServiceBase::run() -{ - assert(s_service != NULL); - - /* Register the control handler. This function is called by the service - * manager to stop the service. The service name that we're passing here - * doesn't have to be valid as we're using SERVICE_WIN32_OWN_PROCESS. */ - s_service->hstatus = RegisterServiceCtrlHandler( - "", (LPHANDLER_FUNCTION)control_handler); - if (!s_service->hstatus) { - return; - } - - s_service->set_status(SERVICE_START_PENDING); - - // TODO: should we expect exceptions? - int err = s_service->run_hook(); - if (err) { - lderr(s_service->cct) << "Failed to start service. Error code: " - << err << dendl; - s_service->set_status(SERVICE_STOPPED); - } else { - s_service->set_status(SERVICE_RUNNING); - } -} - -void ServiceBase::shutdown() -{ - DWORD original_state = status.dwCurrentState; - set_status(SERVICE_STOP_PENDING); - - int err = shutdown_hook(); - if (err) { - derr << "Shutdown service hook failed. Error code: " << err << dendl; - set_status(original_state); - } else { - set_status(SERVICE_STOPPED); - } -} - -void ServiceBase::stop() -{ - DWORD original_state = status.dwCurrentState; - set_status(SERVICE_STOP_PENDING); - - int err = stop_hook(); - if (err) { - derr << "Service stop hook failed. Error code: " << err << dendl; - set_status(original_state); - } else { - set_status(SERVICE_STOPPED); - } -} - -/* This function is registered with the Windows services manager through - * a call to RegisterServiceCtrlHandler() and will be called by the Windows - * service manager asynchronously to stop the service. */ -void ServiceBase::control_handler(DWORD request) -{ - switch (request) { - case SERVICE_CONTROL_STOP: - s_service->stop(); - break; - case SERVICE_CONTROL_SHUTDOWN: - s_service->shutdown(); - break; - default: - break; - } -} - -void ServiceBase::set_status(DWORD current_state, DWORD exit_code) { - static DWORD dwCheckPoint = 1; - if (current_state == SERVICE_RUNNING || current_state == SERVICE_STOPPED) { - status.dwCheckPoint = dwCheckPoint++; - } - - status.dwCurrentState = current_state; - status.dwWin32ExitCode = exit_code; - - if (hstatus) { - ::SetServiceStatus(hstatus, &status); - } -} diff --git a/src/common/service_win32.h b/src/common/service_win32.h deleted file mode 100644 index 5adcdea223f1c..0000000000000 --- a/src/common/service_win32.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2019 SUSE LINUX GmbH - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - -#include "include/compat.h" -#include "common/ceph_context.h" - -class ServiceBase { - -public: - ServiceBase(CephContext *cct_); - virtual ~ServiceBase() {}; - - static int initialize(ServiceBase *service); -protected: - static void run(); - static void control_handler(DWORD request); - - void shutdown(); - void stop(); - - void set_status(DWORD current_state, DWORD exit_code = NO_ERROR); - - /* Subclasses should implement the following service hooks. */ - virtual int run_hook() = 0; - /* Invoked when the service is requested to stop. */ - virtual int stop_hook() = 0; - /* Invoked when the system is shutting down. */ - virtual int shutdown_hook() = 0; - - CephContext *cct; - -private: - /* A handle used when reporting the current status. */ - SERVICE_STATUS_HANDLE hstatus; - /* The current service status. */ - SERVICE_STATUS status; - - /* singleton service instance */ - static ServiceBase *s_service; -}; diff --git a/src/common/win32/SubProcess.cc b/src/common/win32/SubProcess.cc new file mode 100644 index 0000000000000..565cb47f0faae --- /dev/null +++ b/src/common/win32/SubProcess.cc @@ -0,0 +1,304 @@ +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2020 SUSE LINUX GmbH + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include +#include +#include +#include +#include + +#include "common/SubProcess.h" +#include "common/errno.h" +#include "include/ceph_assert.h" +#include "include/compat.h" + +SubProcess::SubProcess(const char *cmd_, std_fd_op stdin_op_, std_fd_op stdout_op_, std_fd_op stderr_op_) : + cmd(cmd_), + cmd_args(), + stdin_op(stdin_op_), + stdout_op(stdout_op_), + stderr_op(stderr_op_), + stdin_pipe_out_fd(-1), + stdout_pipe_in_fd(-1), + stderr_pipe_in_fd(-1), + pid(0), + errstr() { +} + +SubProcess::~SubProcess() { + ceph_assert(!is_spawned()); + ceph_assert(stdin_pipe_out_fd == -1); + ceph_assert(stdout_pipe_in_fd == -1); + ceph_assert(stderr_pipe_in_fd == -1); +} + +void SubProcess::add_cmd_args(const char *arg, ...) { + ceph_assert(!is_spawned()); + + va_list ap; + va_start(ap, arg); + const char *p = arg; + do { + add_cmd_arg(p); + p = va_arg(ap, const char*); + } while (p != NULL); + va_end(ap); +} + +void SubProcess::add_cmd_arg(const char *arg) { + ceph_assert(!is_spawned()); + + cmd_args.push_back(arg); +} + +int SubProcess::get_stdin() const { + ceph_assert(is_spawned()); + ceph_assert(stdin_op == PIPE); + + return stdin_pipe_out_fd; +} + +int SubProcess::get_stdout() const { + ceph_assert(is_spawned()); + ceph_assert(stdout_op == PIPE); + + return stdout_pipe_in_fd; +} + +int SubProcess::get_stderr() const { + ceph_assert(is_spawned()); + ceph_assert(stderr_op == PIPE); + + return stderr_pipe_in_fd; +} + +void SubProcess::close(int &fd) { + if (fd == -1) + return; + + ::close(fd); + fd = -1; +} + +void SubProcess::close_stdin() { + ceph_assert(is_spawned()); + ceph_assert(stdin_op == PIPE); + + close(stdin_pipe_out_fd); +} + +void SubProcess::close_stdout() { + ceph_assert(is_spawned()); + ceph_assert(stdout_op == PIPE); + + close(stdout_pipe_in_fd); +} + +void SubProcess::close_stderr() { + ceph_assert(is_spawned()); + ceph_assert(stderr_op == PIPE); + + close(stderr_pipe_in_fd); +} + +const std::string SubProcess::err() const { + return errstr.str(); +} + +SubProcessTimed::SubProcessTimed(const char *cmd, std_fd_op stdin_op, + std_fd_op stdout_op, std_fd_op stderr_op, + int timeout_, int sigkill_) : + SubProcess(cmd, stdin_op, stdout_op, stderr_op), + timeout(timeout_), + sigkill(sigkill_) { +} + +static bool timedout = false; +void timeout_sighandler(int sig) { + timedout = true; +} + +void SubProcess::close_h(HANDLE &handle) { + if (handle == INVALID_HANDLE_VALUE) + return; + + CloseHandle(handle); + handle = INVALID_HANDLE_VALUE; +} + +int SubProcess::join() { + ceph_assert(is_spawned()); + + close(stdin_pipe_out_fd); + close(stdout_pipe_in_fd); + close(stderr_pipe_in_fd); + + DWORD status = 0; + + if (WaitForSingleObject(proc_handle, INFINITE) != WAIT_FAILED) { + if (!GetExitCodeProcess(proc_handle, &status)) { + errstr << cmd << ": Could not get exit code: " << pid + << ". Error code: " << GetLastError(); + } else if (status) { + errstr << cmd << ": exit status: " << status; + } + } else { + errstr << cmd << ": Waiting for child process failed: " << pid + << ". Error code: " << GetLastError(); + } + + close_h(proc_handle); + pid = 0; + return status; +} + +void SubProcess::kill(int signo) const { + ceph_assert(is_spawned()); + ceph_assert(TerminateProcess(proc_handle, 128 + SIGTERM)); +} + +int SubProcess::spawn() { + std::ostringstream cmdline; + cmdline << cmd; + for (auto& arg : cmd_args) { + cmdline << " " << std::quoted(arg); + } + + STARTUPINFO si = {0}; + PROCESS_INFORMATION pi = {0}; + SECURITY_ATTRIBUTES sa = {0}; + + sa.nLength = sizeof(SECURITY_ATTRIBUTES); + sa.bInheritHandle = TRUE; + sa.lpSecurityDescriptor = NULL; + + HANDLE stdin_r = INVALID_HANDLE_VALUE, stdin_w = INVALID_HANDLE_VALUE, + stdout_r = INVALID_HANDLE_VALUE, stdout_w = INVALID_HANDLE_VALUE, + stderr_r = INVALID_HANDLE_VALUE, stderr_w = INVALID_HANDLE_VALUE; + + if ((stdin_op == PIPE && !CreatePipe(&stdin_r, &stdin_w, &sa, 0)) || + (stdout_op == PIPE && !CreatePipe(&stdout_r, &stdout_w, &sa, 0)) || + (stderr_op == PIPE && !CreatePipe(&stderr_r, &stderr_w, &sa, 0))) { + errstr << cmd << ": CreatePipe failed: " << GetLastError(); + return -1; + } + + // The following handles will be used by the parent process and + // must be marked as non-inheritable. + if ((stdin_op == PIPE && !SetHandleInformation(stdin_w, HANDLE_FLAG_INHERIT, 0)) || + (stdout_op == PIPE && !SetHandleInformation(stdout_r, HANDLE_FLAG_INHERIT, 0)) || + (stderr_op == PIPE && !SetHandleInformation(stderr_r, HANDLE_FLAG_INHERIT, 0))) { + errstr << cmd << ": SetHandleInformation failed: " + << GetLastError(); + goto fail; + } + + si.cb = sizeof(STARTUPINFO); + si.hStdInput = stdin_op == KEEP ? GetStdHandle(STD_INPUT_HANDLE) : stdin_r; + si.hStdOutput = stdout_op == KEEP ? GetStdHandle(STD_OUTPUT_HANDLE) : stdout_w; + si.hStdError = stderr_op == KEEP ? GetStdHandle(STD_ERROR_HANDLE) : stderr_w; + si.dwFlags |= STARTF_USESTDHANDLES; + + stdin_pipe_out_fd = stdin_op == PIPE ? _open_osfhandle((intptr_t)stdin_w, 0) : -1; + stdout_pipe_in_fd = stdout_op == PIPE ? _open_osfhandle((intptr_t)stdout_r, _O_RDONLY) : - 1; + stderr_pipe_in_fd = stderr_op == PIPE ? _open_osfhandle((intptr_t)stderr_r, _O_RDONLY) : -1; + + if (stdin_op == PIPE && stdin_pipe_out_fd == -1 || + stdout_op == PIPE && stdout_pipe_in_fd == -1 || + stderr_op == PIPE && stderr_pipe_in_fd == -1) { + errstr << cmd << ": _open_osfhandle failed: " << GetLastError(); + goto fail; + } + + // We've transfered ownership from those handles. + stdin_w = stdout_r = stderr_r = INVALID_HANDLE_VALUE; + + if (!CreateProcess( + NULL, const_cast(cmdline.str().c_str()), + NULL, NULL, /* No special security attributes */ + 1, /* Inherit handles marked as inheritable */ + 0, /* No special flags */ + NULL, /* Use the same environment variables */ + NULL, /* use the same cwd */ + &si, &pi)) { + errstr << cmd << ": CreateProcess failed: " << GetLastError(); + goto fail; + } + + proc_handle = pi.hProcess; + pid = GetProcessId(proc_handle); + if (!pid) { + errstr << cmd << ": Could not get child process id."; + goto fail; + } + + // The following are used by the subprocess. + CloseHandle(stdin_r); + CloseHandle(stdout_w); + CloseHandle(stderr_w); + CloseHandle(pi.hThread); + return 0; + +fail: + // fd copies + close(stdin_pipe_out_fd); + close(stdout_pipe_in_fd); + close(stderr_pipe_in_fd); + + // the original handles + close_h(stdin_r); + close_h(stdin_w); + close_h(stdout_r); + close_h(stdout_w); + close_h(stderr_r); + close_h(stderr_w); + + // We may consider mapping some of the Windows errors. + return -1; +} + +void SubProcess::exec() { +} + +int SubProcessTimed::spawn() { + if (auto ret = SubProcess::spawn(); ret < 0) { + return ret; + } + + if (timeout > 0) { + waiter = std::thread([&](){ + DWORD wait_status = WaitForSingleObject(proc_handle, timeout * 1000); + ceph_assert(wait_status != WAIT_FAILED); + if (wait_status == WAIT_TIMEOUT) { + // 128 + sigkill is just the return code, which is expected by + // the unit tests and possibly by other code. We can't pick a + // termination signal unless we use window events. + ceph_assert(TerminateProcess(proc_handle, 128 + sigkill)); + timedout = 1; + } + }); + } + return 0; +} + +int SubProcessTimed::join() { + ceph_assert(is_spawned()); + + if (waiter.joinable()) { + waiter.join(); + } + + return SubProcess::join();; +} + +void SubProcessTimed::exec() { +} diff --git a/src/common/win32/blkdev.cc b/src/common/win32/blkdev.cc new file mode 100644 index 0000000000000..bb815a044fc34 --- /dev/null +++ b/src/common/win32/blkdev.cc @@ -0,0 +1,137 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2020 SUSE LINUX GmbH + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include +#include "common/blkdev.h" + +int get_device_by_path(const char *path, char* partition, char* device, + size_t max) +{ + return -EOPNOTSUPP; +} + + +BlkDev::BlkDev(int f) + : fd(f) +{} + +BlkDev::BlkDev(const std::string& devname) + : devname(devname) +{} + +int BlkDev::get_devid(dev_t *id) const +{ + return -EOPNOTSUPP; +} + +const char *BlkDev::sysfsdir() const { + assert(false); // Should never be called on Windows + return ""; +} + +int BlkDev::dev(char *dev, size_t max) const +{ + return -EOPNOTSUPP; +} + +int BlkDev::get_size(int64_t *psize) const +{ + return -EOPNOTSUPP; +} + +bool BlkDev::support_discard() const +{ + return false; +} + +int BlkDev::discard(int64_t offset, int64_t len) const +{ + return -EOPNOTSUPP; +} + +bool BlkDev::is_rotational() const +{ + return false; +} + +int BlkDev::model(char *model, size_t max) const +{ + return -EOPNOTSUPP; +} + +int BlkDev::serial(char *serial, size_t max) const +{ + return -EOPNOTSUPP; +} + +int BlkDev::partition(char *partition, size_t max) const +{ + return -EOPNOTSUPP; +} + +int BlkDev::wholedisk(char *wd, size_t max) const +{ + return -EOPNOTSUPP; +} + +void get_dm_parents(const std::string& dev, std::set *ls) +{ +} + +void get_raw_devices(const std::string& in, + std::set *ls) +{ +} + +int get_vdo_stats_handle(const char *devname, std::string *vdo_name) +{ + return -1; +} + +int64_t get_vdo_stat(int fd, const char *property) +{ + return 0; +} + +bool get_vdo_utilization(int fd, uint64_t *total, uint64_t *avail) +{ + return false; +} + +std::string get_device_id(const std::string& devname, + std::string *err) +{ + if (err) { + *err = "not implemented"; + } + return std::string(); +} + +int block_device_run_smartctl(const char *device, int timeout, + std::string *result) +{ + return -EOPNOTSUPP; +} + +int block_device_get_metrics(const std::string& devname, int timeout, + json_spirit::mValue *result) +{ + return -EOPNOTSUPP; +} + +int block_device_run_nvme(const char *device, const char *vendor, int timeout, + std::string *result) +{ + return -EOPNOTSUPP; +} diff --git a/src/common/win32/dlfcn.cc b/src/common/win32/dlfcn.cc new file mode 100644 index 0000000000000..329d14677bd9d --- /dev/null +++ b/src/common/win32/dlfcn.cc @@ -0,0 +1,38 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2020 SUSE LINUX GmbH + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include +#include + +#include "common/errno.h" +#include "include/dlfcn_compat.h" + + +void* dlopen(const char *filename, int flags) { + return LoadLibrary(filename); +} + +int dlclose(void* handle) { + //FreeLibrary returns 0 on error, as opposed to dlclose. + return !FreeLibrary(handle); +} + +void* dlsym(void* handle, const char* symbol) { + return (void*)GetProcAddress(handle, symbol); +} + +dl_errmsg_t dlerror() { + return win32_lasterror_str(); +} + diff --git a/src/common/win32/dns_resolve.cc b/src/common/win32/dns_resolve.cc new file mode 100644 index 0000000000000..8a7c80bff0434 --- /dev/null +++ b/src/common/win32/dns_resolve.cc @@ -0,0 +1,65 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2019 SUSE LINUX GmbH + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "include/scope_guard.h" +#include "common/dns_resolve.h" +#include "common/debug.h" + +#define dout_subsys ceph_subsys_ + + +namespace ceph { + +int ResolvHWrapper::res_query(const char *hostname, int cls, + int type, u_char *buf, int bufsz) { + return -1; +} + +int ResolvHWrapper::res_search(const char *hostname, int cls, + int type, u_char *buf, int bufsz) { + return -1; +} + +DNSResolver::~DNSResolver() +{ + delete resolv_h; +} + +int DNSResolver::resolve_cname(CephContext *cct, const string& hostname, + string *cname, bool *found) +{ + return -ENOTSUP; +} + +int DNSResolver::resolve_ip_addr(CephContext *cct, const string& hostname, + entity_addr_t *addr) +{ + return -ENOTSUP; +} + +int DNSResolver::resolve_srv_hosts(CephContext *cct, const string& service_name, + const SRV_Protocol trans_protocol, + map *srv_hosts) +{ + return this->resolve_srv_hosts(cct, service_name, trans_protocol, "", srv_hosts); +} + +int DNSResolver::resolve_srv_hosts(CephContext *cct, const string& service_name, + const SRV_Protocol trans_protocol, const string& domain, + map *srv_hosts) +{ + return -ENOTSUP; +} + +} diff --git a/src/common/win32/errno.cc b/src/common/win32/errno.cc new file mode 100644 index 0000000000000..25753779d01cc --- /dev/null +++ b/src/common/win32/errno.cc @@ -0,0 +1,596 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2020 SUSE LINUX GmbH + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + + +#include +#include + +#include "include/int_types.h" +#include +#include + +#include "include/compat.h" +#include "include/int_types.h" +#include "include/types.h" + +// We're only converting errors defined in errno.h, not standard Windows +// system error codes that are usually retrievied using GetLastErrorCode(). +// TODO: consider converting WinSock2 (WSA*) error codes, which are quite +// similar to the errno.h ones. + +__u32 ceph_to_hostos_errno_unsigned(__u32 r) +{ + // using an array like like freebsd_errno.cc might be more readable but + // we have some large values defined by Boost. + switch(r) { + case 1: return EPERM; + case 2: return ENOENT; + case 3: return ESRCH; + case 4: return EINTR; + case 5: return EIO; + case 6: return ENXIO; + case 7: return E2BIG; + case 8: return ENOEXEC; + case 9: return EBADF; + case 10: return ECHILD; + // same as EWOULDBLOCK + case 11: return EAGAIN; + case 12: return ENOMEM; + case 13: return EACCES; + case 14: return EFAULT; + case 15: return ENOTBLK; + case 16: return EBUSY; + case 17: return EEXIST; + case 18: return EXDEV; + case 19: return ENODEV; + case 20: return ENOTDIR; + case 21: return EISDIR; + case 22: return EINVAL; + case 23: return ENFILE; + case 24: return EMFILE; + case 25: return ENOTTY; + case 26: return ETXTBSY; + case 27: return EFBIG; + case 28: return ENOSPC; + case 29: return ESPIPE; + case 30: return EROFS; + case 31: return EMLINK; + case 32: return EPIPE; + case 33: return EDOM; + case 34: return ERANGE; + // same as EDEADLK + case 35: return EDEADLOCK; + case 36: return ENAMETOOLONG; + case 37: return ENOLCK; + case 38: return ENOSYS; + case 39: return ENOTEMPTY; + case 40: return ELOOP; + case 42: return ENOMSG; + case 43: return EIDRM; + case 44: return ECHRNG; + case 45: return EL2NSYNC; + case 46: return EL3HLT; + case 47: return EL3RST; + case 48: return ELNRNG; + case 49: return EUNATCH; + case 50: return ENOCSI; + case 51: return EL2HLT; + case 52: return EBADE; + case 53: return EBADR; + case 54: return EXFULL; + case 55: return ENOANO; + case 56: return EBADRQC; + case 57: return EBADSLT; + case 59: return EBFONT; + case 60: return ENOSTR; + case 61: return ENODATA; + case 62: return ETIME; + case 63: return ENOSR; + case 64: return ENONET; + case 65: return ENOPKG; + case 66: return EREMOTE; + case 67: return ENOLINK; + case 68: return EADV; + case 69: return ESRMNT; + case 70: return ECOMM; + case 71: return EPROTO; + case 72: return EMULTIHOP; + case 73: return EDOTDOT; + case 74: return EBADMSG; + case 75: return EOVERFLOW; + case 76: return ENOTUNIQ; + case 77: return EBADFD; + case 78: return EREMCHG; + case 79: return ELIBACC; + case 80: return ELIBBAD; + case 81: return ELIBSCN; + case 82: return ELIBMAX; + case 83: return ELIBEXEC; + case 84: return EILSEQ; + case 85: return ERESTART; + case 86: return ESTRPIPE; + case 87: return EUSERS; + case 88: return ENOTSOCK; + case 89: return EDESTADDRREQ; + case 90: return EMSGSIZE; + case 91: return EPROTOTYPE; + case 92: return ENOPROTOOPT; + case 93: return EPROTONOSUPPORT; + case 94: return ESOCKTNOSUPPORT; + // same as ENOTSUP + case 95: return EOPNOTSUPP; + case 96: return EPFNOSUPPORT; + case 97: return EAFNOSUPPORT; + case 98: return EADDRINUSE; + case 99: return EADDRNOTAVAIL; + case 100: return ENETDOWN; + case 101: return ENETUNREACH; + case 102: return ENETRESET; + case 103: return ECONNABORTED; + case 104: return ECONNRESET; + case 105: return ENOBUFS; + case 106: return EISCONN; + case 107: return ENOTCONN; + case 108: return ESHUTDOWN; + case 109: return ETOOMANYREFS; + case 110: return ETIMEDOUT; + case 111: return ECONNREFUSED; + case 112: return EHOSTDOWN; + case 113: return EHOSTUNREACH; + case 114: return EALREADY; + case 115: return EINPROGRESS; + case 116: return ESTALE; + case 117: return EUCLEAN; + case 118: return ENOTNAM; + case 119: return ENAVAIL; + case 120: return EISNAM; + case 121: return EREMOTEIO; + case 122: return EDQUOT; + case 123: return ENOMEDIUM; + case 124: return EMEDIUMTYPE; + case 125: return ECANCELED; + case 126: return ENOKEY; + case 127: return EKEYEXPIRED; + case 128: return EKEYREVOKED; + case 129: return EKEYREJECTED; + case 130: return EOWNERDEAD; + case 131: return ENOTRECOVERABLE; + case 132: return ERFKILL; + case 133: return EHWPOISON; + default: + return r; + } +} + +__u32 hostos_to_ceph_errno_unsigned(__u32 r) { + // Windows errno -> Linux errno + switch(r) { + case EPERM: return 1; + case ENOENT: return 2; + case ESRCH: return 3; + case EINTR: return 4; + case EIO: return 5; + case ENXIO: return 6; + case E2BIG: return 7; + case ENOEXEC: return 8; + case EBADF: return 9; + case ECHILD: return 10; + case EAGAIN: return 11; + case EWOULDBLOCK: return 11; + case ENOMEM: return 12; + case EACCES: return 13; + case EFAULT: return 14; + case ENOTBLK: return 15; + case EBUSY: return 16; + case EEXIST: return 17; + case EXDEV: return 18; + case ENODEV: return 19; + case ENOTDIR: return 20; + case EISDIR: return 21; + case EINVAL: return 22; + case ENFILE: return 23; + case EMFILE: return 24; + case ENOTTY: return 25; + case ETXTBSY: return 26; + case EFBIG: return 27; + case ENOSPC: return 28; + case ESPIPE: return 29; + case EROFS: return 30; + case EMLINK: return 31; + case EPIPE: return 32; + case EDOM: return 33; + case ERANGE: return 34; + // same as EDEADLOCK + // case EDEADLK: return 35; + case EDEADLOCK: return 35; + case ENAMETOOLONG: return 36; + case ENOLCK: return 37; + case ENOSYS: return 38; + case ENOTEMPTY: return 39; + case ELOOP: return 40; + case ENOMSG: return 42; + case EIDRM: return 43; + case ECHRNG: return 44; + case EL2NSYNC: return 45; + case EL3HLT: return 46; + case EL3RST: return 47; + case ELNRNG: return 48; + case EUNATCH: return 49; + case ENOCSI: return 50; + case EL2HLT: return 51; + case EBADE: return 52; + case EBADR: return 53; + case EXFULL: return 54; + case ENOANO: return 55; + case EBADRQC: return 56; + case EBADSLT: return 57; + case EBFONT: return 59; + case ENOSTR: return 60; + case ENODATA: return 61; + case ETIME: return 62; + case ENOSR: return 63; + case ENONET: return 64; + case ENOPKG: return 65; + case EREMOTE: return 66; + case ENOLINK: return 67; + case EADV: return 68; + case ESRMNT: return 69; + case ECOMM: return 70; + case EPROTO: return 71; + case EMULTIHOP: return 72; + case EDOTDOT: return 73; + case EBADMSG: return 74; + case EOVERFLOW: return 75; + case ENOTUNIQ: return 76; + case EBADFD: return 77; + case EREMCHG: return 78; + case ELIBACC: return 79; + case ELIBBAD: return 80; + case ELIBSCN: return 81; + case ELIBMAX: return 82; + case ELIBEXEC: return 83; + case EILSEQ: return 84; + // compat.h defines ERESTART as EINTR + // case ERESTART: return 85; + case ESTRPIPE: return 86; + case EUSERS: return 87; + case ENOTSOCK: return 88; + case EDESTADDRREQ: return 89; + case EMSGSIZE: return 90; + case EPROTOTYPE: return 91; + case ENOPROTOOPT: return 92; + case EPROTONOSUPPORT: return 93; + case ESOCKTNOSUPPORT: return 94; + case EOPNOTSUPP: return 95; + case ENOTSUP: return 95; + case EPFNOSUPPORT: return 96; + case EAFNOSUPPORT: return 97; + case EADDRINUSE: return 98; + case EADDRNOTAVAIL: return 99; + case ENETDOWN: return 100; + case ENETUNREACH: return 101; + case ENETRESET: return 102; + case ECONNABORTED: return 103; + case ECONNRESET: return 104; + case ENOBUFS: return 105; + case EISCONN: return 106; + case ENOTCONN: return 107; + case ESHUTDOWN: return 108; + case ETOOMANYREFS: return 109; + case ETIMEDOUT: return 110; + case ECONNREFUSED: return 111; + case EHOSTDOWN: return 112; + case EHOSTUNREACH: return 113; + case EALREADY: return 114; + case EINPROGRESS: return 115; + case ESTALE: return 116; + case EUCLEAN: return 117; + case ENOTNAM: return 118; + case ENAVAIL: return 119; + case EISNAM: return 120; + case EREMOTEIO: return 121; + case EDQUOT: return 122; + case ENOMEDIUM: return 123; + case EMEDIUMTYPE: return 124; + case ECANCELED: return 125; + case ENOKEY: return 126; + case EKEYEXPIRED: return 127; + case EKEYREVOKED: return 128; + case EKEYREJECTED: return 129; + case EOWNERDEAD: return 130; + case ENOTRECOVERABLE: return 131; + case ERFKILL: return 132; + case EHWPOISON: return 133; + default: + return r; + } +} + +__s32 wsae_to_errno_unsigned(__s32 r) +{ + switch(r) { + case WSAEINTR: return EINTR; + case WSAEBADF: return EBADF; + case WSAEACCES: return EACCES; + case WSAEFAULT: return EFAULT; + case WSAEINVAL: return EINVAL; + case WSAEMFILE: return EMFILE; + // Linux defines WSAEWOULDBLOCK as EAGAIN, but not Windows headers. + // Since all ceph code uses EAGAIN instead of EWOULDBLOCK, we'll do + // the same here. + case WSAEWOULDBLOCK: return EAGAIN; + // Some functions (e.g. connect) can return WSAEWOULDBLOCK instead of + // EINPROGRESS. + case WSAEINPROGRESS: return EINPROGRESS; + case WSAEALREADY: return EALREADY; + case WSAENOTSOCK: return ENOTSOCK; + case WSAEDESTADDRREQ: return EDESTADDRREQ; + case WSAEMSGSIZE: return EMSGSIZE; + case WSAEPROTOTYPE: return EPROTOTYPE; + case WSAENOPROTOOPT: return ENOPROTOOPT; + case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT; + case WSAESOCKTNOSUPPORT: return ESOCKTNOSUPPORT; + case WSAEOPNOTSUPP: return EOPNOTSUPP; + case WSAEPFNOSUPPORT: return EPFNOSUPPORT; + case WSAEAFNOSUPPORT: return EAFNOSUPPORT; + case WSAEADDRINUSE: return EADDRINUSE; + case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL; + case WSAENETDOWN: return ENETDOWN; + case WSAENETUNREACH: return ENETUNREACH; + case WSAENETRESET: return ENETRESET; + case WSAECONNABORTED: return ECONNABORTED; + case WSAECONNRESET: return ECONNRESET; + case WSAENOBUFS: return ENOBUFS; + case WSAEISCONN: return EISCONN; + case WSAENOTCONN: return ENOTCONN; + case WSAESHUTDOWN: return ESHUTDOWN; + case WSAETOOMANYREFS: return ETOOMANYREFS; + case WSAETIMEDOUT: return ETIMEDOUT; + case WSAECONNREFUSED: return ECONNREFUSED; + case WSAELOOP: return ELOOP; + case WSAENAMETOOLONG: return ENAMETOOLONG; + case WSAEHOSTDOWN: return EHOSTDOWN; + case WSAEHOSTUNREACH: return EHOSTUNREACH; + case WSAENOTEMPTY: return ENOTEMPTY; + // case WSAEPROCLIM + case WSAEUSERS: return EUSERS; + case WSAEDQUOT: return EDQUOT; + case WSAESTALE: return ESTALE; + case WSAEREMOTE: return EREMOTE; + // case WSASYSNOTREADY + // case WSAVERNOTSUPPORTED + // case WSANOTINITIALISED + case WSAEDISCON: return ESHUTDOWN; + // case WSAENOMORE + case WSAECANCELLED: return ECANCELED; + // We might return EINVAL, but it's probably better if we propagate the + // original error code here. + // case WSAEINVALIDPROCTABLE + // case WSAEINVALIDPROVIDER + // case WSAEPROVIDERFAILEDINIT + // case WSASYSCALLFAILURE + // case WSASERVICE_NOT_FOUND: + // case WSATYPE_NOT_FOUND: + // case WSA_E_NO_MORE: + case WSA_E_CANCELLED: return ECANCELED; + case WSAEREFUSED: return ECONNREFUSED; + case WSAHOST_NOT_FOUND: return EHOSTUNREACH; + case WSATRY_AGAIN: return EAGAIN; + // case WSANO_RECOVERY + // case WSANO_DATA: + default: return r; + } +} + +// converts from linux errno values to host values +__s32 ceph_to_hostos_errno(__s32 r) +{ + int sign = (r < 0 ? -1 : 1); + return ceph_to_hostos_errno_unsigned(abs(r)) * sign; +} + +// converts Host OS errno values to linux/Ceph values +__s32 hostos_to_ceph_errno(__s32 r) +{ + int sign = (r < 0 ? -1 : 1); + return hostos_to_ceph_errno_unsigned(abs(r)) * sign; +} + +__s32 wsae_to_errno(__s32 r) +{ + int sign = (r < 0 ? -1 : 1); + return wsae_to_errno_unsigned(abs(r)) * sign; +} + +__u32 errno_to_ntstatus(__u32 r) { + // errno -> NTSTATUS + // In some cases, there might be more than one applicable NTSTATUS + // value or there might be none. Certain values can be overridden + // when the caller (or whoever is supposed to handle the error) is + // expecting a different NTSTATUS value. + switch(r) { + case 0: return 0; + case EPERM: return STATUS_ACCESS_DENIED; + case ENOENT: return STATUS_OBJECT_NAME_NOT_FOUND; + case ESRCH: return STATUS_NOT_FOUND; + case EINTR: return STATUS_RETRY; + case EIO: return STATUS_DATA_ERROR; + case ENXIO: return STATUS_NOT_FOUND; + case E2BIG: return STATUS_FILE_TOO_LARGE; + case ENOEXEC: return STATUS_ACCESS_DENIED; + case EBADF: return STATUS_INVALID_HANDLE; + case ECHILD: return STATUS_INTERNAL_ERROR; + case EAGAIN: return STATUS_RETRY; + case EWOULDBLOCK: return STATUS_RETRY; + case ENOMEM: return STATUS_NO_MEMORY; + case EACCES: return STATUS_ACCESS_DENIED; + case EFAULT: return STATUS_INVALID_ADDRESS; + case ENOTBLK: return STATUS_BAD_DEVICE_TYPE; + case EBUSY: return STATUS_DEVICE_BUSY; + case EEXIST: return STATUS_OBJECT_NAME_COLLISION; + case EXDEV: return STATUS_NOT_SAME_DEVICE; + case ENODEV: return STATUS_SYSTEM_DEVICE_NOT_FOUND; + case ENOTDIR: return STATUS_NOT_A_DIRECTORY; + case EISDIR: return STATUS_FILE_IS_A_DIRECTORY; + case EINVAL: return STATUS_INVALID_PARAMETER; + case ENFILE: return STATUS_TOO_MANY_OPENED_FILES; + case EMFILE: return STATUS_TOO_MANY_OPENED_FILES; + case ENOTTY: return STATUS_INVALID_PARAMETER; + case ETXTBSY: return STATUS_DEVICE_BUSY; + case EFBIG: return STATUS_FILE_TOO_LARGE; + case ENOSPC: return STATUS_DISK_FULL; + case ESPIPE: return STATUS_INVALID_PARAMETER; + case EROFS: return STATUS_MEDIA_WRITE_PROTECTED; + case EMLINK: return STATUS_TOO_MANY_LINKS; + case EPIPE: return STATUS_PIPE_BROKEN; + case EDOM: return STATUS_INVALID_PARAMETER; + case ERANGE: return STATUS_INVALID_PARAMETER; + // same as EDEADLOCK + // case EDEADLK: return 35; + case EDEADLOCK: return STATUS_POSSIBLE_DEADLOCK; + case ENAMETOOLONG: return STATUS_NAME_TOO_LONG; + case ENOLCK: return STATUS_NOT_LOCKED; + case ENOSYS: return STATUS_NOT_IMPLEMENTED; + case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY; + case ELOOP: return STATUS_TOO_MANY_LINKS; + case ENOMSG: return STATUS_MESSAGE_NOT_FOUND; + case EIDRM: return STATUS_INVALID_PARAMETER; + case ECHRNG: return STATUS_INVALID_PARAMETER; + case EL2NSYNC: return STATUS_INTERNAL_ERROR; + case EL3HLT: return STATUS_INTERNAL_ERROR; + case EL3RST: return STATUS_INTERNAL_ERROR; + case ELNRNG: return STATUS_INTERNAL_ERROR; + case EUNATCH: return STATUS_INTERNAL_ERROR; + case ENOCSI: return STATUS_INTERNAL_ERROR; + case EL2HLT: return STATUS_INTERNAL_ERROR; + case EBADE: return STATUS_INTERNAL_ERROR; + case EBADR: return STATUS_INVALID_HANDLE; + case EXFULL: return STATUS_DISK_FULL; + case ENOANO: return STATUS_INTERNAL_ERROR; + case EBADRQC: return STATUS_INVALID_PARAMETER; + case EBADSLT: return STATUS_INVALID_PARAMETER; + case EBFONT: return STATUS_INVALID_PARAMETER; + case ENOSTR: return STATUS_INVALID_PARAMETER; + case ENODATA: return STATUS_NOT_FOUND; + case ETIME: return STATUS_TIMEOUT; + case ENOSR: return STATUS_INSUFFICIENT_RESOURCES; + case ENONET: return STATUS_NETWORK_UNREACHABLE; + case ENOPKG: return STATUS_NO_SUCH_PACKAGE; + case EREMOTE: return STATUS_INVALID_PARAMETER; + case ENOLINK: return STATUS_INTERNAL_ERROR; + case EADV: return STATUS_INTERNAL_ERROR; + case ESRMNT: return STATUS_INTERNAL_ERROR; + case ECOMM: return STATUS_INTERNAL_ERROR; + case EPROTO: return STATUS_PROTOCOL_NOT_SUPPORTED; + case EMULTIHOP: return STATUS_INTERNAL_ERROR; + case EDOTDOT: return STATUS_INTERNAL_ERROR; + case EBADMSG: return STATUS_INVALID_PARAMETER; + case EOVERFLOW: return STATUS_BUFFER_OVERFLOW; + case ENOTUNIQ: return STATUS_DUPLICATE_NAME; + case EBADFD: return STATUS_INVALID_HANDLE; + case EREMCHG: return STATUS_FILE_RENAMED; + case ELIBACC: return STATUS_DLL_NOT_FOUND; + case ELIBBAD: return STATUS_BAD_DLL_ENTRYPOINT; + case ELIBSCN: return STATUS_BAD_DLL_ENTRYPOINT; + case ELIBMAX: return STATUS_TOO_MANY_OPENED_FILES; + case ELIBEXEC: return STATUS_INVALID_PARAMETER; + case EILSEQ: return STATUS_INVALID_PARAMETER; + // compat.h defines ERESTART as EINTR + // case ERESTART: return 85; + case ESTRPIPE: return STATUS_RETRY; + case EUSERS: return STATUS_TOO_MANY_SIDS; + case ENOTSOCK: return STATUS_INVALID_HANDLE; + case EDESTADDRREQ: return STATUS_INVALID_PARAMETER; + case EMSGSIZE: return STATUS_BUFFER_OVERFLOW; + case EPROTOTYPE: return STATUS_INVALID_PARAMETER; + case ENOPROTOOPT: return STATUS_PROTOCOL_NOT_SUPPORTED; + case EPROTONOSUPPORT: return STATUS_PROTOCOL_NOT_SUPPORTED; + case ESOCKTNOSUPPORT: return STATUS_NOT_SUPPORTED; + case EOPNOTSUPP: return STATUS_NOT_SUPPORTED; + case ENOTSUP: return STATUS_NOT_SUPPORTED; + case EPFNOSUPPORT: return STATUS_PROTOCOL_NOT_SUPPORTED; + case EAFNOSUPPORT: return STATUS_NOT_SUPPORTED; + case EADDRINUSE: return STATUS_ADDRESS_ALREADY_EXISTS; + case EADDRNOTAVAIL: return STATUS_INVALID_ADDRESS; + case ENETDOWN: return STATUS_NETWORK_UNREACHABLE; + case ENETUNREACH: return STATUS_NETWORK_UNREACHABLE; + case ENETRESET: return STATUS_CONNECTION_RESET; + case ECONNABORTED: return STATUS_CONNECTION_ABORTED; + case ECONNRESET: return STATUS_CONNECTION_DISCONNECTED; + case ENOBUFS: return STATUS_BUFFER_TOO_SMALL; + case EISCONN: return STATUS_CONNECTION_ACTIVE; + case ENOTCONN: return 107; + case ESHUTDOWN: return 108; + case ETOOMANYREFS: return 109; + case ETIMEDOUT: return STATUS_TIMEOUT; + case ECONNREFUSED: return STATUS_CONNECTION_REFUSED; + case EHOSTDOWN: return STATUS_FILE_CLOSED; + case EHOSTUNREACH: return STATUS_HOST_UNREACHABLE; + case EALREADY: return STATUS_PENDING; + case EINPROGRESS: return STATUS_PENDING; + case ESTALE: return STATUS_INVALID_HANDLE; + case EUCLEAN: return STATUS_INVALID_PARAMETER; + case ENOTNAM: return STATUS_INVALID_PARAMETER; + case ENAVAIL: return STATUS_INVALID_PARAMETER; + case EISNAM: return STATUS_INVALID_PARAMETER; + case EREMOTEIO: return STATUS_DATA_ERROR; + case EDQUOT: return STATUS_QUOTA_EXCEEDED; + case ENOMEDIUM: return STATUS_NO_MEDIA; + case EMEDIUMTYPE: return STATUS_INVALID_PARAMETER; + case ECANCELED: return STATUS_REQUEST_CANCELED; + case ENOKEY: return STATUS_NO_USER_KEYS; + case EKEYEXPIRED: return STATUS_SMARTCARD_CERT_EXPIRED; + case EKEYREVOKED: return STATUS_IMAGE_CERT_REVOKED; + case EKEYREJECTED: return STATUS_ACCESS_DENIED; + case EOWNERDEAD: return STATUS_INTERNAL_ERROR; + case ENOTRECOVERABLE: return STATUS_INTERNAL_ERROR; + case ERFKILL: return STATUS_INTERNAL_ERROR; + case EHWPOISON: return STATUS_INTERNAL_ERROR; + default: + return STATUS_INTERNAL_ERROR; + } +} + +std::string win32_strerror(int err) +{ + // As opposed to dlerror messages, this has to be freed. + LPSTR msg = NULL; + DWORD msg_len = ::FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + err, + 0, + (LPSTR) &msg, + 0, + NULL); + + std::ostringstream msg_stream; + msg_stream << "(" << err << ") "; + if (!msg_len) { + msg_stream << "Unknown error"; + } + else { + msg_stream << msg; + ::LocalFree(msg); + } + return msg_stream.str(); +} + +std::string win32_lasterror_str() +{ + DWORD err = ::GetLastError(); + return win32_strerror(err); +} diff --git a/src/common/win32/ifaddrs.cc b/src/common/win32/ifaddrs.cc new file mode 100644 index 0000000000000..d7de4a5ff8ae2 --- /dev/null +++ b/src/common/win32/ifaddrs.cc @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include +#include +#include + +#include "include/compat.h" + +int getifaddrs(struct ifaddrs **ifap) +{ + int ret = 0; + + DWORD size, res = 0; + res = GetAdaptersAddresses( + AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, + NULL, NULL, &size); + if (res != ERROR_BUFFER_OVERFLOW) { + errno = ENOMEM; + return -1; + } + + PIP_ADAPTER_ADDRESSES adapter_addrs = (PIP_ADAPTER_ADDRESSES)malloc(size); + res = GetAdaptersAddresses( + AF_UNSPEC, GAA_FLAG_INCLUDE_PREFIX, + NULL, adapter_addrs, &size); + if (res != ERROR_SUCCESS) { + errno = ENOMEM; + return -1; + } + + struct ifaddrs *out_list_head = NULL; + struct ifaddrs *out_list_curr; + + for (PIP_ADAPTER_ADDRESSES curr_addrs = adapter_addrs; + curr_addrs != NULL; + curr_addrs = curr_addrs->Next) { + if (curr_addrs->OperStatus != 1) + continue; + + for (PIP_ADAPTER_UNICAST_ADDRESS unicast_addrs = curr_addrs->FirstUnicastAddress; + unicast_addrs != NULL; + unicast_addrs = unicast_addrs->Next) { + SOCKADDR* unicast_sockaddr = unicast_addrs->Address.lpSockaddr; + if (unicast_sockaddr->sa_family != AF_INET && + unicast_sockaddr->sa_family != AF_INET6) + continue; + out_list_curr = calloc(sizeof(*out_list_curr), 1); + if (!out_list_curr) { + errno = ENOMEM; + ret = -1; + goto out; + } + + out_list_curr->ifa_next = out_list_head; + out_list_head = out_list_curr; + + out_list_curr->ifa_flags = IFF_UP; + if (curr_addrs->IfType == IF_TYPE_SOFTWARE_LOOPBACK) + out_list_curr->ifa_flags |= IFF_LOOPBACK; + + out_list_curr->ifa_addr = (struct sockaddr *) &out_list_curr->in_addrs; + out_list_curr->ifa_netmask = (struct sockaddr *) &out_list_curr->in_netmasks; + out_list_curr->ifa_name = out_list_curr->ad_name; + + if (unicast_sockaddr->sa_family == AF_INET) { + ULONG subnet_mask = 0; + if (ConvertLengthToIpv4Mask(unicast_addrs->OnLinkPrefixLength, &subnet_mask)) { + errno = ENODATA; + ret = -1; + goto out; + } + struct sockaddr_in *addr4 = (struct sockaddr_in *) &out_list_curr->in_addrs; + struct sockaddr_in *netmask4 = (struct sockaddr_in *) &out_list_curr->in_netmasks; + netmask4->sin_family = unicast_sockaddr->sa_family; + addr4->sin_family = unicast_sockaddr->sa_family; + netmask4->sin_addr.S_un.S_addr = subnet_mask; + addr4->sin_addr = ((struct sockaddr_in*) unicast_sockaddr)->sin_addr; + } else { + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *) &out_list_curr->in_addrs; + (*addr6) = *(struct sockaddr_in6 *) unicast_sockaddr; + } + out_list_curr->speed = curr_addrs->TransmitLinkSpeed; + // TODO maybe use friendly name instead of adapter GUID + sprintf_s(out_list_curr->ad_name, + sizeof(out_list_curr->ad_name), + curr_addrs->AdapterName); + } + } + ret = 0; +out: + free(adapter_addrs); + if (ret && out_list_head) + free(out_list_head); + else if (ifap) + *ifap = out_list_head; + + return ret; +} + +void freeifaddrs(struct ifaddrs *ifa) +{ + while (ifa) { + struct ifaddrs *next = ifa->ifa_next; + free(ifa); + ifa = next; + } +} diff --git a/src/common/win32/registry.cc b/src/common/win32/registry.cc new file mode 100644 index 0000000000000..d032e3b602ab8 --- /dev/null +++ b/src/common/win32/registry.cc @@ -0,0 +1,155 @@ +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2020 SUSE LINUX GmbH + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#define dout_context cct +#define dout_subsys ceph_subsys_ + +#include "common/debug.h" +#include "common/errno.h" +#include "common/win32/registry.h" + +RegistryKey::RegistryKey(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey, + bool create_value): cct(cct_) +{ + DWORD status = RegOpenKeyEx(hRootKey, strKey, 0, KEY_ALL_ACCESS, &hKey); + + if (status == ERROR_FILE_NOT_FOUND && create_value) + { + ldout(cct_, 10) << "Creating registry key: " << strKey << dendl; + status = RegCreateKeyEx( + hRootKey, strKey, 0, NULL, REG_OPTION_NON_VOLATILE, + KEY_ALL_ACCESS, NULL, &hKey, NULL); + } + + if (ERROR_SUCCESS != status) { + if (ERROR_FILE_NOT_FOUND == status) { + missingKey = true; + } else { + lderr(cct_) << "Error: " << win32_strerror(status) + << ". Could not open registry key: " + << strKey << dendl; + } + } +} + +RegistryKey::~RegistryKey() { + if (!hKey) + return; + + DWORD status = RegCloseKey(hKey); + if (ERROR_SUCCESS != status) { + derr << "Error: " << win32_strerror(status) + << ". Could not close registry key." << dendl; + } else { + hKey = NULL; + } +} + +int RegistryKey::remove(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey) +{ + DWORD status = RegDeleteKeyEx(hRootKey, strKey, KEY_WOW64_64KEY, 0); + + if (status == ERROR_FILE_NOT_FOUND) + { + ldout(cct_, 20) << "Registry key : " << strKey + << " does not exist." << dendl; + return 0; + } + + if (ERROR_SUCCESS != status) { + lderr(cct_) << "Error: " << win32_strerror(status) + << ". Could not delete registry key: " + << strKey << dendl; + return -EINVAL; + } + + return 0; +} + +int RegistryKey::flush() { + DWORD status = RegFlushKey(hKey); + if (ERROR_SUCCESS != status) { + derr << "Error: " << win32_strerror(status) + << ". Could not flush registry key." << dendl; + return -EINVAL; + } + + return 0; +} + +int RegistryKey::set(LPCTSTR lpValue, DWORD data) +{ + DWORD status = RegSetValueEx(hKey, lpValue, 0, REG_DWORD, + (LPBYTE)&data, sizeof(DWORD)); + if (ERROR_SUCCESS != status) { + derr << "Error: " << win32_strerror(status) + << ". Could not set registry value: " << (char*)lpValue << dendl; + return -EINVAL; + } + + return 0; +} + +int RegistryKey::set(LPCTSTR lpValue, std::string data) +{ + DWORD status = RegSetValueEx(hKey, lpValue, 0, REG_SZ, + (LPBYTE)data.c_str(), data.length()); + if (ERROR_SUCCESS != status) { + derr << "Error: " << win32_strerror(status) + << ". Could not set registry value: " + << (char*)lpValue << dendl; + return -EINVAL; + } + return 0; +} + +int RegistryKey::get(LPCTSTR lpValue, DWORD* value) +{ + DWORD data; + DWORD size = sizeof(data); + DWORD type = REG_DWORD; + DWORD status = RegQueryValueEx(hKey, lpValue, NULL, + &type, (LPBYTE)&data, &size); + if (ERROR_SUCCESS != status) { + derr << "Error: " << win32_strerror(status) + << ". Could not get registry value: " + << (char*)lpValue << dendl; + return -EINVAL; + } + *value = data; + + return 0; +} + +int RegistryKey::get(LPCTSTR lpValue, std::string& value) +{ + std::string data{""}; + DWORD size = 0; + DWORD type = REG_SZ; + DWORD status = RegQueryValueEx(hKey, lpValue, NULL, &type, + (LPBYTE)data.c_str(), &size); + if (ERROR_MORE_DATA == status) { + data.resize(size); + status = RegQueryValueEx(hKey, lpValue, NULL, &type, + (LPBYTE)data.c_str(), &size); + } + + if (ERROR_SUCCESS != status) { + derr << "Error: " << win32_strerror(status) + << ". Could not get registry value: " + << (char*)lpValue << dendl; + return -EINVAL; + } + value.assign(data.c_str()); + + return 0; +} diff --git a/src/common/win32/registry.h b/src/common/win32/registry.h new file mode 100644 index 0000000000000..974d662de2d98 --- /dev/null +++ b/src/common/win32/registry.h @@ -0,0 +1,37 @@ +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2019 SUSE LINUX GmbH + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "include/compat.h" +#include "common/ceph_context.h" + + +class RegistryKey { +public: + RegistryKey(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey, bool create_value); + ~RegistryKey(); + + static remove(CephContext *cct_, HKEY hRootKey, LPCTSTR strKey); + + int flush(); + + int set(LPCTSTR lpValue, DWORD data); + int set(LPCTSTR lpValue, std::string data); + + int get(LPCTSTR lpValue, DWORD* value); + int get(LPCTSTR lpValue, std::string& value); + + HKEY hKey = NULL; + bool missingKey = false; + +private: + CephContext *cct; +}; diff --git a/src/common/win32/service.cc b/src/common/win32/service.cc new file mode 100644 index 0000000000000..df0e834137cbd --- /dev/null +++ b/src/common/win32/service.cc @@ -0,0 +1,137 @@ +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2019 SUSE LINUX GmbH + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#define dout_context cct +#define dout_subsys ceph_subsys_ + +#include "common/debug.h" +#include "common/errno.h" +#include "common/win32/service.h" + +// Initialize the singleton service instance. +ServiceBase *ServiceBase::s_service = NULL; + +ServiceBase::ServiceBase(CephContext *cct_): cct(cct_) +{ + status.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + status.dwCurrentState = SERVICE_START_PENDING; + status.dwWin32ExitCode = NO_ERROR; + status.dwCheckPoint = 0; + /* The estimated time required for the stop operation in ms. */ + status.dwWaitHint = 0; +} + +/* Register service action callbacks */ +int ServiceBase::initialize(ServiceBase *service) +{ + s_service = service; + + SERVICE_TABLE_ENTRY service_table[] = { + {"", (LPSERVICE_MAIN_FUNCTION)run}, + {NULL, NULL} + }; + + /* StartServiceCtrlDispatcher blocks until the service is stopped. */ + if (!StartServiceCtrlDispatcher(service_table)) { + int err = GetLastError(); + lderr(service->cct) << "StartServiceCtrlDispatcher error: " + << err << dendl; + return -EINVAL; + } + return 0; +} + +void WINAPI ServiceBase::run() +{ + assert(s_service != NULL); + + /* Register the control handler. This function is called by the service + * manager to stop the service. The service name that we're passing here + * doesn't have to be valid as we're using SERVICE_WIN32_OWN_PROCESS. */ + s_service->hstatus = RegisterServiceCtrlHandler( + "", (LPHANDLER_FUNCTION)control_handler); + if (!s_service->hstatus) { + return; + } + + s_service->set_status(SERVICE_START_PENDING); + + // TODO: should we expect exceptions? + int err = s_service->run_hook(); + if (err) { + lderr(s_service->cct) << "Failed to start service. Error code: " + << err << dendl; + s_service->set_status(SERVICE_STOPPED); + } else { + s_service->set_status(SERVICE_RUNNING); + } +} + +void ServiceBase::shutdown() +{ + DWORD original_state = status.dwCurrentState; + set_status(SERVICE_STOP_PENDING); + + int err = shutdown_hook(); + if (err) { + derr << "Shutdown service hook failed. Error code: " << err << dendl; + set_status(original_state); + } else { + set_status(SERVICE_STOPPED); + } +} + +void ServiceBase::stop() +{ + DWORD original_state = status.dwCurrentState; + set_status(SERVICE_STOP_PENDING); + + int err = stop_hook(); + if (err) { + derr << "Service stop hook failed. Error code: " << err << dendl; + set_status(original_state); + } else { + set_status(SERVICE_STOPPED); + } +} + +/* This function is registered with the Windows services manager through + * a call to RegisterServiceCtrlHandler() and will be called by the Windows + * service manager asynchronously to stop the service. */ +void ServiceBase::control_handler(DWORD request) +{ + switch (request) { + case SERVICE_CONTROL_STOP: + s_service->stop(); + break; + case SERVICE_CONTROL_SHUTDOWN: + s_service->shutdown(); + break; + default: + break; + } +} + +void ServiceBase::set_status(DWORD current_state, DWORD exit_code) { + static DWORD dwCheckPoint = 1; + if (current_state == SERVICE_RUNNING || current_state == SERVICE_STOPPED) { + status.dwCheckPoint = dwCheckPoint++; + } + + status.dwCurrentState = current_state; + status.dwWin32ExitCode = exit_code; + + if (hstatus) { + ::SetServiceStatus(hstatus, &status); + } +} diff --git a/src/common/win32/service.h b/src/common/win32/service.h new file mode 100644 index 0000000000000..5adcdea223f1c --- /dev/null +++ b/src/common/win32/service.h @@ -0,0 +1,49 @@ +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2019 SUSE LINUX GmbH + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#include "include/compat.h" +#include "common/ceph_context.h" + +class ServiceBase { + +public: + ServiceBase(CephContext *cct_); + virtual ~ServiceBase() {}; + + static int initialize(ServiceBase *service); +protected: + static void run(); + static void control_handler(DWORD request); + + void shutdown(); + void stop(); + + void set_status(DWORD current_state, DWORD exit_code = NO_ERROR); + + /* Subclasses should implement the following service hooks. */ + virtual int run_hook() = 0; + /* Invoked when the service is requested to stop. */ + virtual int stop_hook() = 0; + /* Invoked when the system is shutting down. */ + virtual int shutdown_hook() = 0; + + CephContext *cct; + +private: + /* A handle used when reporting the current status. */ + SERVICE_STATUS_HANDLE hstatus; + /* The current service status. */ + SERVICE_STATUS status; + + /* singleton service instance */ + static ServiceBase *s_service; +}; diff --git a/src/common/win32_errno.cc b/src/common/win32_errno.cc deleted file mode 100644 index 25753779d01cc..0000000000000 --- a/src/common/win32_errno.cc +++ /dev/null @@ -1,596 +0,0 @@ -// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- -// vim: ts=8 sw=2 smarttab -/* - * Ceph - scalable distributed file system - * - * Copyright (C) 2020 SUSE LINUX GmbH - * - * This is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License version 2.1, as published by the Free Software - * Foundation. See file COPYING. - * - */ - - -#include -#include - -#include "include/int_types.h" -#include -#include - -#include "include/compat.h" -#include "include/int_types.h" -#include "include/types.h" - -// We're only converting errors defined in errno.h, not standard Windows -// system error codes that are usually retrievied using GetLastErrorCode(). -// TODO: consider converting WinSock2 (WSA*) error codes, which are quite -// similar to the errno.h ones. - -__u32 ceph_to_hostos_errno_unsigned(__u32 r) -{ - // using an array like like freebsd_errno.cc might be more readable but - // we have some large values defined by Boost. - switch(r) { - case 1: return EPERM; - case 2: return ENOENT; - case 3: return ESRCH; - case 4: return EINTR; - case 5: return EIO; - case 6: return ENXIO; - case 7: return E2BIG; - case 8: return ENOEXEC; - case 9: return EBADF; - case 10: return ECHILD; - // same as EWOULDBLOCK - case 11: return EAGAIN; - case 12: return ENOMEM; - case 13: return EACCES; - case 14: return EFAULT; - case 15: return ENOTBLK; - case 16: return EBUSY; - case 17: return EEXIST; - case 18: return EXDEV; - case 19: return ENODEV; - case 20: return ENOTDIR; - case 21: return EISDIR; - case 22: return EINVAL; - case 23: return ENFILE; - case 24: return EMFILE; - case 25: return ENOTTY; - case 26: return ETXTBSY; - case 27: return EFBIG; - case 28: return ENOSPC; - case 29: return ESPIPE; - case 30: return EROFS; - case 31: return EMLINK; - case 32: return EPIPE; - case 33: return EDOM; - case 34: return ERANGE; - // same as EDEADLK - case 35: return EDEADLOCK; - case 36: return ENAMETOOLONG; - case 37: return ENOLCK; - case 38: return ENOSYS; - case 39: return ENOTEMPTY; - case 40: return ELOOP; - case 42: return ENOMSG; - case 43: return EIDRM; - case 44: return ECHRNG; - case 45: return EL2NSYNC; - case 46: return EL3HLT; - case 47: return EL3RST; - case 48: return ELNRNG; - case 49: return EUNATCH; - case 50: return ENOCSI; - case 51: return EL2HLT; - case 52: return EBADE; - case 53: return EBADR; - case 54: return EXFULL; - case 55: return ENOANO; - case 56: return EBADRQC; - case 57: return EBADSLT; - case 59: return EBFONT; - case 60: return ENOSTR; - case 61: return ENODATA; - case 62: return ETIME; - case 63: return ENOSR; - case 64: return ENONET; - case 65: return ENOPKG; - case 66: return EREMOTE; - case 67: return ENOLINK; - case 68: return EADV; - case 69: return ESRMNT; - case 70: return ECOMM; - case 71: return EPROTO; - case 72: return EMULTIHOP; - case 73: return EDOTDOT; - case 74: return EBADMSG; - case 75: return EOVERFLOW; - case 76: return ENOTUNIQ; - case 77: return EBADFD; - case 78: return EREMCHG; - case 79: return ELIBACC; - case 80: return ELIBBAD; - case 81: return ELIBSCN; - case 82: return ELIBMAX; - case 83: return ELIBEXEC; - case 84: return EILSEQ; - case 85: return ERESTART; - case 86: return ESTRPIPE; - case 87: return EUSERS; - case 88: return ENOTSOCK; - case 89: return EDESTADDRREQ; - case 90: return EMSGSIZE; - case 91: return EPROTOTYPE; - case 92: return ENOPROTOOPT; - case 93: return EPROTONOSUPPORT; - case 94: return ESOCKTNOSUPPORT; - // same as ENOTSUP - case 95: return EOPNOTSUPP; - case 96: return EPFNOSUPPORT; - case 97: return EAFNOSUPPORT; - case 98: return EADDRINUSE; - case 99: return EADDRNOTAVAIL; - case 100: return ENETDOWN; - case 101: return ENETUNREACH; - case 102: return ENETRESET; - case 103: return ECONNABORTED; - case 104: return ECONNRESET; - case 105: return ENOBUFS; - case 106: return EISCONN; - case 107: return ENOTCONN; - case 108: return ESHUTDOWN; - case 109: return ETOOMANYREFS; - case 110: return ETIMEDOUT; - case 111: return ECONNREFUSED; - case 112: return EHOSTDOWN; - case 113: return EHOSTUNREACH; - case 114: return EALREADY; - case 115: return EINPROGRESS; - case 116: return ESTALE; - case 117: return EUCLEAN; - case 118: return ENOTNAM; - case 119: return ENAVAIL; - case 120: return EISNAM; - case 121: return EREMOTEIO; - case 122: return EDQUOT; - case 123: return ENOMEDIUM; - case 124: return EMEDIUMTYPE; - case 125: return ECANCELED; - case 126: return ENOKEY; - case 127: return EKEYEXPIRED; - case 128: return EKEYREVOKED; - case 129: return EKEYREJECTED; - case 130: return EOWNERDEAD; - case 131: return ENOTRECOVERABLE; - case 132: return ERFKILL; - case 133: return EHWPOISON; - default: - return r; - } -} - -__u32 hostos_to_ceph_errno_unsigned(__u32 r) { - // Windows errno -> Linux errno - switch(r) { - case EPERM: return 1; - case ENOENT: return 2; - case ESRCH: return 3; - case EINTR: return 4; - case EIO: return 5; - case ENXIO: return 6; - case E2BIG: return 7; - case ENOEXEC: return 8; - case EBADF: return 9; - case ECHILD: return 10; - case EAGAIN: return 11; - case EWOULDBLOCK: return 11; - case ENOMEM: return 12; - case EACCES: return 13; - case EFAULT: return 14; - case ENOTBLK: return 15; - case EBUSY: return 16; - case EEXIST: return 17; - case EXDEV: return 18; - case ENODEV: return 19; - case ENOTDIR: return 20; - case EISDIR: return 21; - case EINVAL: return 22; - case ENFILE: return 23; - case EMFILE: return 24; - case ENOTTY: return 25; - case ETXTBSY: return 26; - case EFBIG: return 27; - case ENOSPC: return 28; - case ESPIPE: return 29; - case EROFS: return 30; - case EMLINK: return 31; - case EPIPE: return 32; - case EDOM: return 33; - case ERANGE: return 34; - // same as EDEADLOCK - // case EDEADLK: return 35; - case EDEADLOCK: return 35; - case ENAMETOOLONG: return 36; - case ENOLCK: return 37; - case ENOSYS: return 38; - case ENOTEMPTY: return 39; - case ELOOP: return 40; - case ENOMSG: return 42; - case EIDRM: return 43; - case ECHRNG: return 44; - case EL2NSYNC: return 45; - case EL3HLT: return 46; - case EL3RST: return 47; - case ELNRNG: return 48; - case EUNATCH: return 49; - case ENOCSI: return 50; - case EL2HLT: return 51; - case EBADE: return 52; - case EBADR: return 53; - case EXFULL: return 54; - case ENOANO: return 55; - case EBADRQC: return 56; - case EBADSLT: return 57; - case EBFONT: return 59; - case ENOSTR: return 60; - case ENODATA: return 61; - case ETIME: return 62; - case ENOSR: return 63; - case ENONET: return 64; - case ENOPKG: return 65; - case EREMOTE: return 66; - case ENOLINK: return 67; - case EADV: return 68; - case ESRMNT: return 69; - case ECOMM: return 70; - case EPROTO: return 71; - case EMULTIHOP: return 72; - case EDOTDOT: return 73; - case EBADMSG: return 74; - case EOVERFLOW: return 75; - case ENOTUNIQ: return 76; - case EBADFD: return 77; - case EREMCHG: return 78; - case ELIBACC: return 79; - case ELIBBAD: return 80; - case ELIBSCN: return 81; - case ELIBMAX: return 82; - case ELIBEXEC: return 83; - case EILSEQ: return 84; - // compat.h defines ERESTART as EINTR - // case ERESTART: return 85; - case ESTRPIPE: return 86; - case EUSERS: return 87; - case ENOTSOCK: return 88; - case EDESTADDRREQ: return 89; - case EMSGSIZE: return 90; - case EPROTOTYPE: return 91; - case ENOPROTOOPT: return 92; - case EPROTONOSUPPORT: return 93; - case ESOCKTNOSUPPORT: return 94; - case EOPNOTSUPP: return 95; - case ENOTSUP: return 95; - case EPFNOSUPPORT: return 96; - case EAFNOSUPPORT: return 97; - case EADDRINUSE: return 98; - case EADDRNOTAVAIL: return 99; - case ENETDOWN: return 100; - case ENETUNREACH: return 101; - case ENETRESET: return 102; - case ECONNABORTED: return 103; - case ECONNRESET: return 104; - case ENOBUFS: return 105; - case EISCONN: return 106; - case ENOTCONN: return 107; - case ESHUTDOWN: return 108; - case ETOOMANYREFS: return 109; - case ETIMEDOUT: return 110; - case ECONNREFUSED: return 111; - case EHOSTDOWN: return 112; - case EHOSTUNREACH: return 113; - case EALREADY: return 114; - case EINPROGRESS: return 115; - case ESTALE: return 116; - case EUCLEAN: return 117; - case ENOTNAM: return 118; - case ENAVAIL: return 119; - case EISNAM: return 120; - case EREMOTEIO: return 121; - case EDQUOT: return 122; - case ENOMEDIUM: return 123; - case EMEDIUMTYPE: return 124; - case ECANCELED: return 125; - case ENOKEY: return 126; - case EKEYEXPIRED: return 127; - case EKEYREVOKED: return 128; - case EKEYREJECTED: return 129; - case EOWNERDEAD: return 130; - case ENOTRECOVERABLE: return 131; - case ERFKILL: return 132; - case EHWPOISON: return 133; - default: - return r; - } -} - -__s32 wsae_to_errno_unsigned(__s32 r) -{ - switch(r) { - case WSAEINTR: return EINTR; - case WSAEBADF: return EBADF; - case WSAEACCES: return EACCES; - case WSAEFAULT: return EFAULT; - case WSAEINVAL: return EINVAL; - case WSAEMFILE: return EMFILE; - // Linux defines WSAEWOULDBLOCK as EAGAIN, but not Windows headers. - // Since all ceph code uses EAGAIN instead of EWOULDBLOCK, we'll do - // the same here. - case WSAEWOULDBLOCK: return EAGAIN; - // Some functions (e.g. connect) can return WSAEWOULDBLOCK instead of - // EINPROGRESS. - case WSAEINPROGRESS: return EINPROGRESS; - case WSAEALREADY: return EALREADY; - case WSAENOTSOCK: return ENOTSOCK; - case WSAEDESTADDRREQ: return EDESTADDRREQ; - case WSAEMSGSIZE: return EMSGSIZE; - case WSAEPROTOTYPE: return EPROTOTYPE; - case WSAENOPROTOOPT: return ENOPROTOOPT; - case WSAEPROTONOSUPPORT: return EPROTONOSUPPORT; - case WSAESOCKTNOSUPPORT: return ESOCKTNOSUPPORT; - case WSAEOPNOTSUPP: return EOPNOTSUPP; - case WSAEPFNOSUPPORT: return EPFNOSUPPORT; - case WSAEAFNOSUPPORT: return EAFNOSUPPORT; - case WSAEADDRINUSE: return EADDRINUSE; - case WSAEADDRNOTAVAIL: return EADDRNOTAVAIL; - case WSAENETDOWN: return ENETDOWN; - case WSAENETUNREACH: return ENETUNREACH; - case WSAENETRESET: return ENETRESET; - case WSAECONNABORTED: return ECONNABORTED; - case WSAECONNRESET: return ECONNRESET; - case WSAENOBUFS: return ENOBUFS; - case WSAEISCONN: return EISCONN; - case WSAENOTCONN: return ENOTCONN; - case WSAESHUTDOWN: return ESHUTDOWN; - case WSAETOOMANYREFS: return ETOOMANYREFS; - case WSAETIMEDOUT: return ETIMEDOUT; - case WSAECONNREFUSED: return ECONNREFUSED; - case WSAELOOP: return ELOOP; - case WSAENAMETOOLONG: return ENAMETOOLONG; - case WSAEHOSTDOWN: return EHOSTDOWN; - case WSAEHOSTUNREACH: return EHOSTUNREACH; - case WSAENOTEMPTY: return ENOTEMPTY; - // case WSAEPROCLIM - case WSAEUSERS: return EUSERS; - case WSAEDQUOT: return EDQUOT; - case WSAESTALE: return ESTALE; - case WSAEREMOTE: return EREMOTE; - // case WSASYSNOTREADY - // case WSAVERNOTSUPPORTED - // case WSANOTINITIALISED - case WSAEDISCON: return ESHUTDOWN; - // case WSAENOMORE - case WSAECANCELLED: return ECANCELED; - // We might return EINVAL, but it's probably better if we propagate the - // original error code here. - // case WSAEINVALIDPROCTABLE - // case WSAEINVALIDPROVIDER - // case WSAEPROVIDERFAILEDINIT - // case WSASYSCALLFAILURE - // case WSASERVICE_NOT_FOUND: - // case WSATYPE_NOT_FOUND: - // case WSA_E_NO_MORE: - case WSA_E_CANCELLED: return ECANCELED; - case WSAEREFUSED: return ECONNREFUSED; - case WSAHOST_NOT_FOUND: return EHOSTUNREACH; - case WSATRY_AGAIN: return EAGAIN; - // case WSANO_RECOVERY - // case WSANO_DATA: - default: return r; - } -} - -// converts from linux errno values to host values -__s32 ceph_to_hostos_errno(__s32 r) -{ - int sign = (r < 0 ? -1 : 1); - return ceph_to_hostos_errno_unsigned(abs(r)) * sign; -} - -// converts Host OS errno values to linux/Ceph values -__s32 hostos_to_ceph_errno(__s32 r) -{ - int sign = (r < 0 ? -1 : 1); - return hostos_to_ceph_errno_unsigned(abs(r)) * sign; -} - -__s32 wsae_to_errno(__s32 r) -{ - int sign = (r < 0 ? -1 : 1); - return wsae_to_errno_unsigned(abs(r)) * sign; -} - -__u32 errno_to_ntstatus(__u32 r) { - // errno -> NTSTATUS - // In some cases, there might be more than one applicable NTSTATUS - // value or there might be none. Certain values can be overridden - // when the caller (or whoever is supposed to handle the error) is - // expecting a different NTSTATUS value. - switch(r) { - case 0: return 0; - case EPERM: return STATUS_ACCESS_DENIED; - case ENOENT: return STATUS_OBJECT_NAME_NOT_FOUND; - case ESRCH: return STATUS_NOT_FOUND; - case EINTR: return STATUS_RETRY; - case EIO: return STATUS_DATA_ERROR; - case ENXIO: return STATUS_NOT_FOUND; - case E2BIG: return STATUS_FILE_TOO_LARGE; - case ENOEXEC: return STATUS_ACCESS_DENIED; - case EBADF: return STATUS_INVALID_HANDLE; - case ECHILD: return STATUS_INTERNAL_ERROR; - case EAGAIN: return STATUS_RETRY; - case EWOULDBLOCK: return STATUS_RETRY; - case ENOMEM: return STATUS_NO_MEMORY; - case EACCES: return STATUS_ACCESS_DENIED; - case EFAULT: return STATUS_INVALID_ADDRESS; - case ENOTBLK: return STATUS_BAD_DEVICE_TYPE; - case EBUSY: return STATUS_DEVICE_BUSY; - case EEXIST: return STATUS_OBJECT_NAME_COLLISION; - case EXDEV: return STATUS_NOT_SAME_DEVICE; - case ENODEV: return STATUS_SYSTEM_DEVICE_NOT_FOUND; - case ENOTDIR: return STATUS_NOT_A_DIRECTORY; - case EISDIR: return STATUS_FILE_IS_A_DIRECTORY; - case EINVAL: return STATUS_INVALID_PARAMETER; - case ENFILE: return STATUS_TOO_MANY_OPENED_FILES; - case EMFILE: return STATUS_TOO_MANY_OPENED_FILES; - case ENOTTY: return STATUS_INVALID_PARAMETER; - case ETXTBSY: return STATUS_DEVICE_BUSY; - case EFBIG: return STATUS_FILE_TOO_LARGE; - case ENOSPC: return STATUS_DISK_FULL; - case ESPIPE: return STATUS_INVALID_PARAMETER; - case EROFS: return STATUS_MEDIA_WRITE_PROTECTED; - case EMLINK: return STATUS_TOO_MANY_LINKS; - case EPIPE: return STATUS_PIPE_BROKEN; - case EDOM: return STATUS_INVALID_PARAMETER; - case ERANGE: return STATUS_INVALID_PARAMETER; - // same as EDEADLOCK - // case EDEADLK: return 35; - case EDEADLOCK: return STATUS_POSSIBLE_DEADLOCK; - case ENAMETOOLONG: return STATUS_NAME_TOO_LONG; - case ENOLCK: return STATUS_NOT_LOCKED; - case ENOSYS: return STATUS_NOT_IMPLEMENTED; - case ENOTEMPTY: return STATUS_DIRECTORY_NOT_EMPTY; - case ELOOP: return STATUS_TOO_MANY_LINKS; - case ENOMSG: return STATUS_MESSAGE_NOT_FOUND; - case EIDRM: return STATUS_INVALID_PARAMETER; - case ECHRNG: return STATUS_INVALID_PARAMETER; - case EL2NSYNC: return STATUS_INTERNAL_ERROR; - case EL3HLT: return STATUS_INTERNAL_ERROR; - case EL3RST: return STATUS_INTERNAL_ERROR; - case ELNRNG: return STATUS_INTERNAL_ERROR; - case EUNATCH: return STATUS_INTERNAL_ERROR; - case ENOCSI: return STATUS_INTERNAL_ERROR; - case EL2HLT: return STATUS_INTERNAL_ERROR; - case EBADE: return STATUS_INTERNAL_ERROR; - case EBADR: return STATUS_INVALID_HANDLE; - case EXFULL: return STATUS_DISK_FULL; - case ENOANO: return STATUS_INTERNAL_ERROR; - case EBADRQC: return STATUS_INVALID_PARAMETER; - case EBADSLT: return STATUS_INVALID_PARAMETER; - case EBFONT: return STATUS_INVALID_PARAMETER; - case ENOSTR: return STATUS_INVALID_PARAMETER; - case ENODATA: return STATUS_NOT_FOUND; - case ETIME: return STATUS_TIMEOUT; - case ENOSR: return STATUS_INSUFFICIENT_RESOURCES; - case ENONET: return STATUS_NETWORK_UNREACHABLE; - case ENOPKG: return STATUS_NO_SUCH_PACKAGE; - case EREMOTE: return STATUS_INVALID_PARAMETER; - case ENOLINK: return STATUS_INTERNAL_ERROR; - case EADV: return STATUS_INTERNAL_ERROR; - case ESRMNT: return STATUS_INTERNAL_ERROR; - case ECOMM: return STATUS_INTERNAL_ERROR; - case EPROTO: return STATUS_PROTOCOL_NOT_SUPPORTED; - case EMULTIHOP: return STATUS_INTERNAL_ERROR; - case EDOTDOT: return STATUS_INTERNAL_ERROR; - case EBADMSG: return STATUS_INVALID_PARAMETER; - case EOVERFLOW: return STATUS_BUFFER_OVERFLOW; - case ENOTUNIQ: return STATUS_DUPLICATE_NAME; - case EBADFD: return STATUS_INVALID_HANDLE; - case EREMCHG: return STATUS_FILE_RENAMED; - case ELIBACC: return STATUS_DLL_NOT_FOUND; - case ELIBBAD: return STATUS_BAD_DLL_ENTRYPOINT; - case ELIBSCN: return STATUS_BAD_DLL_ENTRYPOINT; - case ELIBMAX: return STATUS_TOO_MANY_OPENED_FILES; - case ELIBEXEC: return STATUS_INVALID_PARAMETER; - case EILSEQ: return STATUS_INVALID_PARAMETER; - // compat.h defines ERESTART as EINTR - // case ERESTART: return 85; - case ESTRPIPE: return STATUS_RETRY; - case EUSERS: return STATUS_TOO_MANY_SIDS; - case ENOTSOCK: return STATUS_INVALID_HANDLE; - case EDESTADDRREQ: return STATUS_INVALID_PARAMETER; - case EMSGSIZE: return STATUS_BUFFER_OVERFLOW; - case EPROTOTYPE: return STATUS_INVALID_PARAMETER; - case ENOPROTOOPT: return STATUS_PROTOCOL_NOT_SUPPORTED; - case EPROTONOSUPPORT: return STATUS_PROTOCOL_NOT_SUPPORTED; - case ESOCKTNOSUPPORT: return STATUS_NOT_SUPPORTED; - case EOPNOTSUPP: return STATUS_NOT_SUPPORTED; - case ENOTSUP: return STATUS_NOT_SUPPORTED; - case EPFNOSUPPORT: return STATUS_PROTOCOL_NOT_SUPPORTED; - case EAFNOSUPPORT: return STATUS_NOT_SUPPORTED; - case EADDRINUSE: return STATUS_ADDRESS_ALREADY_EXISTS; - case EADDRNOTAVAIL: return STATUS_INVALID_ADDRESS; - case ENETDOWN: return STATUS_NETWORK_UNREACHABLE; - case ENETUNREACH: return STATUS_NETWORK_UNREACHABLE; - case ENETRESET: return STATUS_CONNECTION_RESET; - case ECONNABORTED: return STATUS_CONNECTION_ABORTED; - case ECONNRESET: return STATUS_CONNECTION_DISCONNECTED; - case ENOBUFS: return STATUS_BUFFER_TOO_SMALL; - case EISCONN: return STATUS_CONNECTION_ACTIVE; - case ENOTCONN: return 107; - case ESHUTDOWN: return 108; - case ETOOMANYREFS: return 109; - case ETIMEDOUT: return STATUS_TIMEOUT; - case ECONNREFUSED: return STATUS_CONNECTION_REFUSED; - case EHOSTDOWN: return STATUS_FILE_CLOSED; - case EHOSTUNREACH: return STATUS_HOST_UNREACHABLE; - case EALREADY: return STATUS_PENDING; - case EINPROGRESS: return STATUS_PENDING; - case ESTALE: return STATUS_INVALID_HANDLE; - case EUCLEAN: return STATUS_INVALID_PARAMETER; - case ENOTNAM: return STATUS_INVALID_PARAMETER; - case ENAVAIL: return STATUS_INVALID_PARAMETER; - case EISNAM: return STATUS_INVALID_PARAMETER; - case EREMOTEIO: return STATUS_DATA_ERROR; - case EDQUOT: return STATUS_QUOTA_EXCEEDED; - case ENOMEDIUM: return STATUS_NO_MEDIA; - case EMEDIUMTYPE: return STATUS_INVALID_PARAMETER; - case ECANCELED: return STATUS_REQUEST_CANCELED; - case ENOKEY: return STATUS_NO_USER_KEYS; - case EKEYEXPIRED: return STATUS_SMARTCARD_CERT_EXPIRED; - case EKEYREVOKED: return STATUS_IMAGE_CERT_REVOKED; - case EKEYREJECTED: return STATUS_ACCESS_DENIED; - case EOWNERDEAD: return STATUS_INTERNAL_ERROR; - case ENOTRECOVERABLE: return STATUS_INTERNAL_ERROR; - case ERFKILL: return STATUS_INTERNAL_ERROR; - case EHWPOISON: return STATUS_INTERNAL_ERROR; - default: - return STATUS_INTERNAL_ERROR; - } -} - -std::string win32_strerror(int err) -{ - // As opposed to dlerror messages, this has to be freed. - LPSTR msg = NULL; - DWORD msg_len = ::FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - err, - 0, - (LPSTR) &msg, - 0, - NULL); - - std::ostringstream msg_stream; - msg_stream << "(" << err << ") "; - if (!msg_len) { - msg_stream << "Unknown error"; - } - else { - msg_stream << msg; - ::LocalFree(msg); - } - return msg_stream.str(); -} - -std::string win32_lasterror_str() -{ - DWORD err = ::GetLastError(); - return win32_strerror(err); -}