diff options
Diffstat (limited to 'src/libnetdata/os')
-rw-r--r-- | src/libnetdata/os/close_range.c | 98 | ||||
-rw-r--r-- | src/libnetdata/os/close_range.h | 12 | ||||
-rw-r--r-- | src/libnetdata/os/get_pid_max.c | 45 | ||||
-rw-r--r-- | src/libnetdata/os/os-windows-wrappers.c | 61 | ||||
-rw-r--r-- | src/libnetdata/os/os-windows-wrappers.h | 18 | ||||
-rw-r--r-- | src/libnetdata/os/os.h | 4 | ||||
-rw-r--r-- | src/libnetdata/os/setproctitle.c | 31 | ||||
-rw-r--r-- | src/libnetdata/os/setproctitle.h | 8 | ||||
-rw-r--r-- | src/libnetdata/os/waitid.c | 72 | ||||
-rw-r--r-- | src/libnetdata/os/waitid.h | 48 |
10 files changed, 260 insertions, 137 deletions
diff --git a/src/libnetdata/os/close_range.c b/src/libnetdata/os/close_range.c new file mode 100644 index 000000000..56d5c2527 --- /dev/null +++ b/src/libnetdata/os/close_range.c @@ -0,0 +1,98 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "../libnetdata.h" + +static int fd_is_valid(int fd) { + errno_clear(); + return fcntl(fd, F_GETFD) != -1 || errno != EBADF; +} + +int os_get_fd_open_max(void) { + static int fd_open_max = CLOSE_RANGE_FD_MAX; + + if(fd_open_max != CLOSE_RANGE_FD_MAX) + return fd_open_max; + + if(fd_open_max == CLOSE_RANGE_FD_MAX || fd_open_max == -1) { + struct rlimit rl; + if (getrlimit(RLIMIT_NOFILE, &rl) == 0 && rl.rlim_max != RLIM_INFINITY) + fd_open_max = rl.rlim_max; + } + +#ifdef _SC_OPEN_MAX + if(fd_open_max == CLOSE_RANGE_FD_MAX || fd_open_max == -1) { + fd_open_max = sysconf(_SC_OPEN_MAX); + } +#endif + + if(fd_open_max == CLOSE_RANGE_FD_MAX || fd_open_max == -1) { + // Arbitrary default if everything else fails + fd_open_max = 65535; + } + + return fd_open_max; +} + +void os_close_range(int first, int last) { +#if defined(HAVE_CLOSE_RANGE) + if(close_range(first, last, 0) == 0) return; +#endif + +#if defined(OS_LINUX) + DIR *dir = opendir("/proc/self/fd"); + if (dir != NULL) { + struct dirent *entry; + while ((entry = readdir(dir)) != NULL) { + int fd = str2i(entry->d_name); + if (fd >= first && (last == CLOSE_RANGE_FD_MAX || fd <= last) && fd_is_valid(fd)) + (void)close(fd); + } + closedir(dir); + return; + } +#endif + + // Fallback to looping through all file descriptors if necessary + if (last == CLOSE_RANGE_FD_MAX) + last = os_get_fd_open_max(); + + for (int fd = first; fd <= last; fd++) { + if (fd_is_valid(fd)) (void)close(fd); + } +} + +static int compare_ints(const void *a, const void *b) { + int int_a = *((int*)a); + int int_b = *((int*)b); + return (int_a > int_b) - (int_a < int_b); +} + +void os_close_all_non_std_open_fds_except(const int fds[], size_t fds_num) { + if (fds_num == 0 || fds == NULL) { + os_close_range(STDERR_FILENO + 1, CLOSE_RANGE_FD_MAX); + return; + } + + // copy the fds array to ensure we will not alter them + int fds_copy[fds_num]; + memcpy(fds_copy, fds, sizeof(fds_copy)); + + qsort(fds_copy, fds_num, sizeof(int), compare_ints); + + int start = STDERR_FILENO + 1; + size_t i = 0; + + // filter out all fds with a number smaller than our start + for (; i < fds_num; i++) + if(fds_copy[i] >= start) break; + + // call os_close_range() as many times as needed + for (; i < fds_num; i++) { + if (fds_copy[i] > start) + os_close_range(start, fds_copy[i] - 1); + + start = fds_copy[i] + 1; + } + + os_close_range(start, CLOSE_RANGE_FD_MAX); +} diff --git a/src/libnetdata/os/close_range.h b/src/libnetdata/os/close_range.h new file mode 100644 index 000000000..e3cb93798 --- /dev/null +++ b/src/libnetdata/os/close_range.h @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef CLOSE_RANGE_H +#define CLOSE_RANGE_H + +#define CLOSE_RANGE_FD_MAX (int)(~0U) + +int os_get_fd_open_max(void); +void os_close_range(int first, int last); +void os_close_all_non_std_open_fds_except(const int fds[], size_t fds_num); + +#endif //CLOSE_RANGE_H diff --git a/src/libnetdata/os/get_pid_max.c b/src/libnetdata/os/get_pid_max.c index 45027961a..70372a743 100644 --- a/src/libnetdata/os/get_pid_max.c +++ b/src/libnetdata/os/get_pid_max.c @@ -2,13 +2,27 @@ #include "../libnetdata.h" -pid_t pid_max = 32768; +pid_t pid_max = 4194304; + pid_t os_get_system_pid_max(void) { + static bool read = false; + if(read) return pid_max; + read = true; + #if defined(OS_MACOS) + int mib[2]; + int maxproc; + size_t len = sizeof(maxproc); + + mib[0] = CTL_KERN; + mib[1] = KERN_MAXPROC; + + if (sysctl(mib, 2, &maxproc, &len, NULL, 0) == -1) { + pid_max = 99999; // Fallback value + nd_log(NDLS_DAEMON, NDLP_ERR, "Cannot find system max pid. Assuming %d.", pid_max); + } + else pid_max = (pid_t)maxproc; - // As we currently do not know a solution to query pid_max from the os - // we use the number defined in bsd/sys/proc_internal.h in XNU sources - pid_max = 99999; return pid_max; #elif defined(OS_FREEBSD) @@ -17,41 +31,40 @@ pid_t os_get_system_pid_max(void) { if (unlikely(GETSYSCTL_BY_NAME("kern.pid_max", tmp_pid_max))) { pid_max = 99999; - netdata_log_error("Assuming system's maximum pid is %d.", pid_max); - } else { - pid_max = tmp_pid_max; + nd_log(NDLS_DAEMON, NDLP_ERR, "Cannot get system max pid. Assuming %d.", pid_max); } + else + pid_max = tmp_pid_max; return pid_max; #elif defined(OS_LINUX) - static char read = 0; - if(unlikely(read)) return pid_max; - read = 1; - char filename[FILENAME_MAX + 1]; snprintfz(filename, FILENAME_MAX, "%s/proc/sys/kernel/pid_max", netdata_configured_host_prefix?netdata_configured_host_prefix:""); unsigned long long max = 0; if(read_single_number_file(filename, &max) != 0) { - netdata_log_error("Cannot open file '%s'. Assuming system supports %d pids.", filename, pid_max); + nd_log(NDLS_DAEMON, NDLP_ERR, "Cannot open file '%s'. Assuming system supports %d pids.", filename, pid_max); return pid_max; } if(!max) { - netdata_log_error("Cannot parse file '%s'. Assuming system supports %d pids.", filename, pid_max); + nd_log(NDLS_DAEMON, NDLP_ERR, "Cannot parse file '%s'. Assuming system supports %d pids.", filename, pid_max); return pid_max; } pid_max = (pid_t) max; return pid_max; -#else +#elif defined(OS_WINDOWS) - // just a big default + pid_max = (pid_t)0x7FFFFFFF; + return pid_max; + +#else - pid_max = 4194304; + // return the default return pid_max; #endif diff --git a/src/libnetdata/os/os-windows-wrappers.c b/src/libnetdata/os/os-windows-wrappers.c new file mode 100644 index 000000000..64076eae2 --- /dev/null +++ b/src/libnetdata/os/os-windows-wrappers.c @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "../libnetdata.h" + +#if defined(OS_WINDOWS) +#include <windows.h> + +long netdata_registry_get_dword_from_open_key(unsigned int *out, void *lKey, char *name) +{ + DWORD length = 260; + return RegQueryValueEx(lKey, name, NULL, NULL, (LPBYTE) out, &length); +} + +bool netdata_registry_get_dword(unsigned int *out, void *hKey, char *subKey, char *name) +{ + HKEY lKey; + bool status = true; + long ret = RegOpenKeyEx(hKey, + subKey, + 0, + KEY_READ, + &lKey); + if (ret != ERROR_SUCCESS) + return false; + + ret = netdata_registry_get_dword_from_open_key(out, lKey, name); + if (ret != ERROR_SUCCESS) + status = false; + + RegCloseKey(lKey); + + return status; +} + +long netdata_registry_get_string_from_open_key(char *out, unsigned int length, void *lKey, char *name) +{ + return RegQueryValueEx(lKey, name, NULL, NULL, (LPBYTE) out, &length); +} + +bool netdata_registry_get_string(char *out, unsigned int length, void *hKey, char *subKey, char *name) +{ + HKEY lKey; + bool status = true; + long ret = RegOpenKeyEx(hKey, + subKey, + 0, + KEY_READ, + &lKey); + if (ret != ERROR_SUCCESS) + return false; + + ret = netdata_registry_get_string_from_open_key(out, length, lKey, name); + if (ret != ERROR_SUCCESS) + status = false; + + RegCloseKey(lKey); + + return status; +} + +#endif diff --git a/src/libnetdata/os/os-windows-wrappers.h b/src/libnetdata/os/os-windows-wrappers.h new file mode 100644 index 000000000..5ae73043a --- /dev/null +++ b/src/libnetdata/os/os-windows-wrappers.h @@ -0,0 +1,18 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef NETDATA_OS_WINDOWS_WRAPPERS_H +#define NETDATA_OS_WINDOWS_WRAPPERS_H + +#include "../libnetdata.h" + +#if defined(OS_WINDOWS) +#define NETDATA_WIN_DETECTION_METHOD "Windows API/Registry" + +long netdata_registry_get_dword_from_open_key(unsigned int *out, void *lKey, char *name); +bool netdata_registry_get_dword(unsigned int *out, void *hKey, char *subKey, char *name); + +long netdata_registry_get_string_from_open_key(char *out, unsigned int length, void *lKey, char *name); +bool netdata_registry_get_string(char *out, unsigned int length, void *hKey, char *subKey, char *name); + +#endif // OS_WINDOWS +#endif //NETDATA_OS_WINDOWS_WRAPPERS_H diff --git a/src/libnetdata/os/os.h b/src/libnetdata/os/os.h index 350096159..15e74faa7 100644 --- a/src/libnetdata/os/os.h +++ b/src/libnetdata/os/os.h @@ -7,12 +7,13 @@ #include <sys/syscall.h> #endif +#include "setproctitle.h" +#include "close_range.h" #include "setresuid.h" #include "setresgid.h" #include "getgrouplist.h" #include "adjtimex.h" #include "gettid.h" -#include "waitid.h" #include "get_pid_max.h" #include "get_system_cpus.h" #include "tinysleep.h" @@ -20,6 +21,7 @@ #include "setenv.h" #include "os-freebsd-wrappers.h" #include "os-macos-wrappers.h" +#include "os-windows-wrappers.h" // ===================================================================================================================== // common defs for Apple/FreeBSD/Linux diff --git a/src/libnetdata/os/setproctitle.c b/src/libnetdata/os/setproctitle.c new file mode 100644 index 000000000..d93158202 --- /dev/null +++ b/src/libnetdata/os/setproctitle.c @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "../libnetdata.h" +#include "setproctitle.h" + +void os_setproctitle(const char *new_name, const int argc, const char **argv) { +#ifdef HAVE_SYS_PRCTL_H + // Set the process name (comm) + prctl(PR_SET_NAME, new_name, 0, 0, 0); +#endif + +#ifdef __FreeBSD__ + // Set the process name on FreeBSD + setproctitle("%s", new_name); +#endif + + if(argc && argv) { + // replace with spaces all parameters found (except argv[0]) + for(int i = 1; i < argc ;i++) { + char *s = (char *)&argv[i][0]; + while(*s != '\0') *s++ = ' '; + } + + // overwrite argv[0] + size_t len = strlen(new_name); + const size_t argv0_len = strlen(argv[0]); + strncpyz((char *)argv[0], new_name, MIN(len, argv0_len)); + while(len < argv0_len) + ((char *)argv[0])[len++] = ' '; + } +} diff --git a/src/libnetdata/os/setproctitle.h b/src/libnetdata/os/setproctitle.h new file mode 100644 index 000000000..0e7211b26 --- /dev/null +++ b/src/libnetdata/os/setproctitle.h @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0-or-later + +#ifndef SETPROCTITLE_H +#define SETPROCTITLE_H + +void os_setproctitle(const char *new_name, int argc, const char **argv); + +#endif //SETPROCTITLE_H diff --git a/src/libnetdata/os/waitid.c b/src/libnetdata/os/waitid.c deleted file mode 100644 index b78d704ed..000000000 --- a/src/libnetdata/os/waitid.c +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "../libnetdata.h" - -int os_waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options) { -#if defined(HAVE_WAITID) - return waitid(idtype, id, infop, options); -#else - // emulate waitid() using waitpid() - - // a cache for WNOWAIT - static const struct pid_status empty = { 0, 0 }; - static __thread struct pid_status last = { 0, 0 }; // the cache - struct pid_status current = { 0, 0 }; - - // zero the infop structure - memset(infop, 0, sizeof(*infop)); - - // from the infop structure we use only 3 fields: - // - si_pid - // - si_code - // - si_status - // so, we update only these 3 - - switch(idtype) { - case P_ALL: - current.pid = waitpid((pid_t)-1, ¤t.status, options); - if(options & WNOWAIT) - last = current; - else - last = empty; - break; - - case P_PID: - if(last.pid == (pid_t)id) { - current = last; - last = empty; - } - else - current.pid = waitpid((pid_t)id, ¤t.status, options); - - break; - - default: - errno = ENOSYS; - return -1; - } - - if (current.pid > 0) { - if (WIFEXITED(current.status)) { - infop->si_code = CLD_EXITED; - infop->si_status = WEXITSTATUS(current.status); - } else if (WIFSIGNALED(current.status)) { - infop->si_code = WTERMSIG(current.status) == SIGABRT ? CLD_DUMPED : CLD_KILLED; - infop->si_status = WTERMSIG(current.status); - } else if (WIFSTOPPED(current.status)) { - infop->si_code = CLD_STOPPED; - infop->si_status = WSTOPSIG(current.status); - } else if (WIFCONTINUED(current.status)) { - infop->si_code = CLD_CONTINUED; - infop->si_status = SIGCONT; - } - infop->si_pid = current.pid; - return 0; - } else if (current.pid == 0) { - // No change in state, depends on WNOHANG - return 0; - } - - return -1; -#endif -} diff --git a/src/libnetdata/os/waitid.h b/src/libnetdata/os/waitid.h deleted file mode 100644 index 9e1fd6be7..000000000 --- a/src/libnetdata/os/waitid.h +++ /dev/null @@ -1,48 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later - -#ifndef NETDATA_WAITID_H -#define NETDATA_WAITID_H - -#include "config.h" -#include <sys/types.h> -#include <signal.h> - -#ifdef HAVE_SYS_WAIT_H -#include <sys/wait.h> -#endif - -#ifndef WNOWAIT -#define WNOWAIT 0x01000000 -#endif - -#ifndef WEXITED -#define WEXITED 4 -#endif - -#if !defined(HAVE_WAITID) -typedef enum -{ - P_ALL, /* Wait for any child. */ - P_PID, /* Wait for specified process. */ - P_PGID, /* Wait for members of process group. */ - P_PIDFD, /* Wait for the child referred by the PID file descriptor. */ -} idtype_t; - -struct pid_status { - pid_t pid; - int status; -}; - -#if defined(OS_WINDOWS) && !defined(__CYGWIN__) -typedef uint32_t id_t; -typedef struct { - int si_code; /* Signal code. */ - int si_status; /* Exit value or signal. */ - pid_t si_pid; /* Sending process ID. */ -} siginfo_t; -#endif -#endif - -int os_waitid(idtype_t idtype, id_t id, siginfo_t *infop, int options); - -#endif //NETDATA_WAITID_H |