From 19fcec84d8d7d21e796c7624e521b60d28ee21ed Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 20:45:59 +0200 Subject: Adding upstream version 16.2.11+ds. Signed-off-by: Daniel Baumann --- src/common/win32/SubProcess.cc | 306 ++++++++++++++++++ src/common/win32/blkdev.cc | 137 ++++++++ src/common/win32/dlfcn.cc | 38 +++ src/common/win32/dns_resolve.cc | 65 ++++ src/common/win32/errno.cc | 652 ++++++++++++++++++++++++++++++++++++++ src/common/win32/event_logging.mc | 35 ++ src/common/win32/ifaddrs.cc | 109 +++++++ src/common/win32/registry.cc | 165 ++++++++++ src/common/win32/registry.h | 38 +++ src/common/win32/service.cc | 156 +++++++++ src/common/win32/service.h | 49 +++ src/common/win32/syslog.cc | 77 +++++ 12 files changed, 1827 insertions(+) create mode 100644 src/common/win32/SubProcess.cc create mode 100644 src/common/win32/blkdev.cc create mode 100644 src/common/win32/dlfcn.cc create mode 100644 src/common/win32/dns_resolve.cc create mode 100644 src/common/win32/errno.cc create mode 100644 src/common/win32/event_logging.mc create mode 100644 src/common/win32/ifaddrs.cc create mode 100644 src/common/win32/registry.cc create mode 100644 src/common/win32/registry.h create mode 100644 src/common/win32/service.cc create mode 100644 src/common/win32/service.h create mode 100644 src/common/win32/syslog.cc (limited to 'src/common/win32') diff --git a/src/common/win32/SubProcess.cc b/src/common/win32/SubProcess.cc new file mode 100644 index 000000000..ce6b851e0 --- /dev/null +++ b/src/common/win32/SubProcess.cc @@ -0,0 +1,306 @@ +/* + * 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); + + int 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(); + status = -ECHILD; + } else if (status) { + errstr << cmd << ": exit status: " << status; + } + } else { + errstr << cmd << ": Waiting for child process failed: " << pid + << ". Error code: " << GetLastError(); + status = -ECHILD; + } + + 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 000000000..bb815a044 --- /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 000000000..329d14677 --- /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 000000000..8a7c80bff --- /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 000000000..bac9320a3 --- /dev/null +++ b/src/common/win32/errno.cc @@ -0,0 +1,652 @@ +// -*- 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" +#include "include/fs_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(__s32 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. + r = abs(r); + + 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 STATUS_CONNECTION_DISCONNECTED; + case ESHUTDOWN: return STATUS_SYSTEM_SHUTDOWN; + case ETOOMANYREFS: return STATUS_TOO_MANY_LINKS; + 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); +} + +static const ceph::unordered_map cephfs_errno_to_ntstatus = { + {CEPHFS_EBLOCKLISTED, STATUS_SYSTEM_SHUTDOWN}, + {CEPHFS_EPERM, STATUS_ACCESS_DENIED}, + {CEPHFS_ESTALE, STATUS_INVALID_HANDLE}, + {CEPHFS_ENOSPC, STATUS_DISK_FULL}, + {CEPHFS_ETIMEDOUT, STATUS_TIMEOUT}, + {CEPHFS_EIO, STATUS_DATA_ERROR}, + {CEPHFS_ENOTCONN, STATUS_CONNECTION_DISCONNECTED}, + {CEPHFS_EEXIST, STATUS_OBJECT_NAME_COLLISION}, + {CEPHFS_EINTR, STATUS_RETRY}, + {CEPHFS_EINVAL, STATUS_INVALID_PARAMETER}, + {CEPHFS_EBADF, STATUS_INVALID_HANDLE}, + {CEPHFS_EROFS, STATUS_MEDIA_WRITE_PROTECTED}, + {CEPHFS_EAGAIN, STATUS_RETRY}, + {CEPHFS_EACCES, STATUS_ACCESS_DENIED}, + {CEPHFS_ELOOP, STATUS_TOO_MANY_LINKS}, + {CEPHFS_EISDIR, STATUS_FILE_IS_A_DIRECTORY}, + {CEPHFS_ENOENT, STATUS_OBJECT_NAME_NOT_FOUND}, + {CEPHFS_ENOTDIR, STATUS_NOT_A_DIRECTORY}, + {CEPHFS_ENAMETOOLONG, STATUS_NAME_TOO_LONG}, + {CEPHFS_EBUSY, STATUS_DEVICE_BUSY}, + {CEPHFS_EDQUOT, STATUS_QUOTA_EXCEEDED}, + {CEPHFS_EFBIG, STATUS_FILE_TOO_LARGE}, + {CEPHFS_ERANGE, STATUS_INVALID_PARAMETER}, + {CEPHFS_ENXIO, STATUS_NOT_FOUND}, + {CEPHFS_ECANCELED, STATUS_REQUEST_CANCELED}, + {CEPHFS_ENODATA, STATUS_NOT_FOUND}, + {CEPHFS_EOPNOTSUPP, STATUS_NOT_SUPPORTED}, + {CEPHFS_EXDEV, STATUS_NOT_SAME_DEVICE}, + {CEPHFS_ENOMEM, STATUS_NO_MEMORY}, + {CEPHFS_ENOTRECOVERABLE, STATUS_INTERNAL_ERROR}, + {CEPHFS_ENOSYS, STATUS_NOT_IMPLEMENTED}, + {CEPHFS_ENOTEMPTY, STATUS_DIRECTORY_NOT_EMPTY}, + {CEPHFS_EDEADLK, STATUS_POSSIBLE_DEADLOCK}, + {CEPHFS_EDOM, STATUS_INVALID_PARAMETER}, + {CEPHFS_EMLINK, STATUS_TOO_MANY_LINKS}, + {CEPHFS_ETIME, STATUS_TIMEOUT}, + {CEPHFS_EOLDSNAPC, STATUS_DATA_ERROR} +}; + +__u32 cephfs_errno_to_ntsatus(int cephfs_errno) +{ + cephfs_errno = abs(cephfs_errno); + + if (cephfs_errno == 0) + return 0; + + auto it = cephfs_errno_to_ntstatus.find(cephfs_errno); + if (it != cephfs_errno_to_ntstatus.end()) + return it->second; + return STATUS_INTERNAL_ERROR; +} diff --git a/src/common/win32/event_logging.mc b/src/common/win32/event_logging.mc new file mode 100644 index 000000000..3d08889aa --- /dev/null +++ b/src/common/win32/event_logging.mc @@ -0,0 +1,35 @@ +SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS + Informational=0x1:STATUS_SEVERITY_INFORMATIONAL + Warning=0x2:STATUS_SEVERITY_WARNING + Error=0x3:STATUS_SEVERITY_ERROR + ) + + +MessageId=0x0001 +Severity=Success +SymbolicName=SUCCESS_EVENTMSG +Language=English +%1 +. + +MessageId=0x0002 +Severity=Informational +SymbolicName=INFO_EVENTMSG +Language=English +%1 +. + +MessageId=0x0003 +Severity=Warning +SymbolicName=WARN_EVENTMSG +Language=English +%1 +. + +MessageId=0x0004 +Severity=Error +SymbolicName=ERROR_EVENTMSG +Language=English +%1 +. + diff --git a/src/common/win32/ifaddrs.cc b/src/common/win32/ifaddrs.cc new file mode 100644 index 000000000..d7de4a5ff --- /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 000000000..85ab80df9 --- /dev/null +++ b/src/common/win32/registry.cc @@ -0,0 +1,165 @@ +/* + * 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, bool& value) +{ + DWORD value_dw = 0; + int r = get(lpValue, value_dw); + if (!r) { + value = !!value_dw; + } + return r; +} + +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 000000000..fdaf9708a --- /dev/null +++ b/src/common/win32/registry.h @@ -0,0 +1,38 @@ +/* + * 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, bool& value); + 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 000000000..846c5d09d --- /dev/null +++ b/src/common/win32/service.cc @@ -0,0 +1,156 @@ +/* + * 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) { + lderr(s_service->cct) << "Could not initialize service control handler. " + << "Error: " << GetLastError() << dendl; + return; + } + + s_service->set_status(SERVICE_START_PENDING); + + // TODO: should we expect exceptions? + ldout(s_service->cct, 5) << "Starting service." << dendl; + int err = s_service->run_hook(); + if (err) { + lderr(s_service->cct) << "Failed to start service. Error code: " + << err << dendl; + s_service->shutdown(true); + } else { + ldout(s_service->cct, 5) << "Successfully started service." << dendl; + s_service->set_status(SERVICE_RUNNING); + } +} + +void ServiceBase::shutdown(bool ignore_errors) +{ + 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; + if (ignore_errors) { + derr << "Ignoring shutdown hook failure, marking the service as stopped." + << dendl; + set_status(SERVICE_STOPPED); + } else { + derr << "Reverting to original service state." << dendl; + set_status(original_state); + } + } else { + dout(5) << "Shutdown hook completed." << dendl; + 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 { + dout(5) << "Successfully stopped service." << dendl; + 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) { + dout(5) << "Updating service service status (" << current_state + << ") and exit code(" << exit_code << ")." << dendl; + ::SetServiceStatus(hstatus, &status); + } else { + derr << "Service control handler not initialized. Cannot " + << "update service status (" << current_state + << ") and exit code(" << exit_code << ")." << dendl; + } +} diff --git a/src/common/win32/service.h b/src/common/win32/service.h new file mode 100644 index 000000000..20d37a876 --- /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(bool ignore_errors = false); + 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/syslog.cc b/src/common/win32/syslog.cc new file mode 100644 index 000000000..7a1a90c9b --- /dev/null +++ b/src/common/win32/syslog.cc @@ -0,0 +1,77 @@ +#include +#include +#include "event_logging.h" +#include "common/code_environment.h" + +static HANDLE g_event_source = NULL; + +bool get_event_source() +{ + if (!g_event_source) { + HANDLE temp = RegisterEventSourceA(NULL, get_process_name_cpp().c_str()); + if (!temp) + return false; + + if (InterlockedCompareExchangePointer(&g_event_source, temp, NULL)) { + // There already was an event source, let's cleanup the one that we've + // just created. + DeregisterEventSource(temp); + } + } + + return true; +} + +void write_event_log_entry(int level, const char* msg) +{ + if (!get_event_source()) { + return; + } + + WORD type; + DWORD event_id; + switch (level) { + case LOG_DEBUG: + event_id = SUCCESS_EVENTMSG; + type = EVENTLOG_SUCCESS; + break; + + case LOG_INFO: + case LOG_NOTICE: + event_id = INFO_EVENTMSG; + type = EVENTLOG_INFORMATION_TYPE; + break; + + case LOG_WARNING: + event_id = WARN_EVENTMSG; + type = EVENTLOG_WARNING_TYPE; + break; + + default: + event_id = ERROR_EVENTMSG; + type = EVENTLOG_ERROR_TYPE; + } + + ReportEventA(g_event_source, type, + 0, event_id, NULL, 1, 0, &msg, NULL); +} + +void syslog(int priority, const char* format, ...) +{ + va_list args; + va_start(args, format); + + size_t length = (size_t)_vscprintf(format, args) + 1; + + char* buffer = (char*) malloc(length); + if (NULL == buffer) { + va_end(args); + return; + } + + vsnprintf_s(buffer, length, length - 1, format, args); + va_end(args); + + write_event_log_entry(LOG_PRI(priority), buffer); + free(buffer); +} -- cgit v1.2.3