diff options
author | Costa Tsaousis <costa@netdata.cloud> | 2022-10-05 14:13:46 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-10-05 14:13:46 +0300 |
commit | 8fc3b351a2e7fc96eced8f924de2e9cec9842128 (patch) | |
tree | bde41c66573ccaf8876c280e00742cc6096b587c /libnetdata/popen | |
parent | 6850878e697d66dc90b9af1e750b22238c63c292 (diff) |
Allow netdata plugins to expose functions for querying more information about specific charts (#13720)
* function renames and code cleanup in popen.c; no actual code changes
* netdata popen() now opens both child process stdin and stdout and returns FILE * for both
* pass both input and output to parser structures
* updated rrdset to call custom functions
* RRDSET FUNCTION leading calls for both sync and async operation
* put RRDSET functions to a separate file
* added format and timeout at function definition
* support for synchronous (internal plugins) and asynchronous (external plugins and children) functions
* /api/v1/function endpoint
* functions are now attached to the host and there is a dictionary view per chart
* functions implemented at plugins.d
* remove the defer until keyword hook from plugins.d when it is done
* stream sender implementation of functions
* sanitization of all functions so that certain characters are only allowed
* strictier sanitization
* common max size
* 1st working plugins.d example
* always init inflight dictionary
* properly destroy dictionaries to avoid parallel insertion of items
* add more debugging on disconnection reasons
* add more debugging on disconnection reasons again
* streaming receiver respects newlines
* dont use the same fp for both streaming receive and send
* dont free dbengine memory with internal checks
* make sender proceed in the buffer
* added timing info and garbage collection at plugins.d
* added info about routing nodes
* added info about routing nodes with delay
* added more info about delays
* added more info about delays again
* signal sending thread to wake up
* streaming version labeling and commented code to support capabilities
* added functions to /api/v1/data, /api/v1/charts, /api/v1/chart, /api/v1/info
* redirect top output to stdout
* address coverity findings
* fix resource leaks of popen
* log attempts to connect to individual destinations
* better messages
* properly parse destinations
* try to find a function from the most matching to the least matching
* log added streaming destinations
* rotate destinations bypassing a node in the middle that does not accept our connection
* break the loops properly
* use typedef to define callbacks
* capabilities negotiation during streaming
* functions exposed upstream based on capabilities; compression disabled per node persisting reconnects; always try to connect with all capabilities
* restore functionality to lookup functions
* better logging of capabilities
* remove old versions from capabilities when a newer version is there
* fix formatting
* optimization for plugins.d rrdlabels to avoid creating and destructing dictionaries all the time
* delayed health initialization for rrddim and rrdset
* cleanup health initialization
* fix for popen() not returning the right value
* add health worker jobs for initializing rrdset and rrddim
* added content type support for functions; apps.plugin permanent function to display all the processes
* fixes for functions parameters parsing in apps.plugin
* fix for process matching in apps.plugiin
* first working function for apps.plugin
* Dashboard ACL is disabled for functions; Function errors are all in JSON format
* apps.plugin function processes returns json table
* use json_escape_string() to escape message
* fix formatting
* apps.plugin exposes all its metrics to function processes
* fix json formatting when filtering out some rows
* reopen the internal pipe of rrdpush in case of errors
* misplaced statement
* do not use buffer->len
* support for GLOBAL functions (functions that are not linked to a chart
* added /api/v1/functions endpoint; removed format from the FUNCTIONS api;
* swagger documentation about the new api end points
* added plugins.d documentation about functions
* never re-close a file
* remove uncessesary ifdef
* fixed issues identified by codacy
* fix for null label value
* make edit-config copy-and-paste friendly
* Revert "make edit-config copy-and-paste friendly"
This reverts commit 54500c0e0a97f65a0c66c4d34e966f6a9056698e.
* reworked sender handshake to fix coverity findings
* timeout is zero, for both send_timeout() and recv_timeout()
* properly detect that parent closed the socket
* support caching of function responses; limit function response to 10MB; added protection from malformed function responses
* disabled excessive logging
* added units to apps.plugin function processes and normalized all values to be human readable
* shorter field names
* fixed issues reported
* fixed apps.plugin error response; tested that pluginsd can properly handle faulty responses
* use double linked list macros for double linked list management
* faster apps.plugin function printing by minimizing file operations
* added memory percentage
* fix compatibility issues with older compilers and FreeBSD
* rrdpush sender code cleanup; rrhost structure cleanup from sender flags and variables;
* fix letftover variable in ifdef
* apps.plugin: do not call detach from the thread; exit immediately when input is broken
* exclude AR charts from health
* flush cleaner; prefer sender output
* clarity
* do not fill the cbuffer if not connected
* fix
* dont enabled host->sender if streaming is not enabled; send host label updates to parent;
* functions are only available through ACLK
* Prepared statement reports only in dev mode
* fix AR chart detection
* fix for streaming not being enabling itself
* more cleanup of sender and receiver structures
* moved read-only flags and configuration options to rrdhost->options
* fixed merge with master
* fix for incomplete rename
* prevent service thread from working on charts that are being collected
Co-authored-by: Stelios Fragkakis <52996999+stelfrag@users.noreply.github.com>
Diffstat (limited to 'libnetdata/popen')
-rw-r--r-- | libnetdata/popen/popen.c | 437 | ||||
-rw-r--r-- | libnetdata/popen/popen.h | 26 |
2 files changed, 257 insertions, 206 deletions
diff --git a/libnetdata/popen/popen.c b/libnetdata/popen/popen.c index eaeffd32dd..b67d6b096b 100644 --- a/libnetdata/popen/popen.c +++ b/libnetdata/popen/popen.c @@ -2,81 +2,129 @@ #include "../libnetdata.h" -static pthread_mutex_t myp_lock; -static int myp_tracking = 0; +// ---------------------------------------------------------------------------- +// popen with tracking -struct mypopen { +static pthread_mutex_t netdata_popen_tracking_mutex; +static bool netdata_popen_tracking_enabled = false; + +struct netdata_popen { pid_t pid; - struct mypopen *next; - struct mypopen *prev; + struct netdata_popen *next; + struct netdata_popen *prev; }; -static struct mypopen *mypopen_root = NULL; +static struct netdata_popen *netdata_popen_root = NULL; // myp_add_lock takes the lock if we're tracking. -static void myp_add_lock(void) { - if (myp_tracking == 0) +static void netdata_popen_tracking_lock(void) { + if(!netdata_popen_tracking_enabled) return; - netdata_mutex_lock(&myp_lock); + netdata_mutex_lock(&netdata_popen_tracking_mutex); } // myp_add_unlock release the lock if we're tracking. -static void myp_add_unlock(void) { - if (myp_tracking == 0) +static void netdata_popen_tracking_unlock(void) { + if(!netdata_popen_tracking_enabled) return; - netdata_mutex_unlock(&myp_lock); + netdata_mutex_unlock(&netdata_popen_tracking_mutex); } // myp_add_locked adds pid if we're tracking. // myp_add_lock must have been called previously. -static void myp_add_locked(pid_t pid) { - struct mypopen *mp; - - if (myp_tracking == 0) +static void netdata_popen_tracking_add_pid_unsafe(pid_t pid) { + if(!netdata_popen_tracking_enabled) return; - mp = mallocz(sizeof(struct mypopen)); + struct netdata_popen *mp; + + mp = mallocz(sizeof(struct netdata_popen)); mp->pid = pid; - mp->next = mypopen_root; - mp->prev = NULL; - if (mypopen_root != NULL) - mypopen_root->prev = mp; - mypopen_root = mp; - netdata_mutex_unlock(&myp_lock); + DOUBLE_LINKED_LIST_PREPEND_UNSAFE(netdata_popen_root, mp, prev, next); } // myp_del deletes pid if we're tracking. -static void myp_del(pid_t pid) { - struct mypopen *mp; - - if (myp_tracking == 0) +static void netdata_popen_tracking_del_pid(pid_t pid) { + if(!netdata_popen_tracking_enabled) return; - netdata_mutex_lock(&myp_lock); - for (mp = mypopen_root; mp != NULL; mp = mp->next) { - if (mp->pid == pid) { - if (mp->next != NULL) - mp->next->prev = mp->prev; - if (mp->prev != NULL) - mp->prev->next = mp->next; - if (mypopen_root == mp) - mypopen_root = mp->next; - freez(mp); + struct netdata_popen *mp; + + netdata_mutex_lock(&netdata_popen_tracking_mutex); + + DOUBLE_LINKED_LIST_FOREACH_FORWARD(netdata_popen_root, mp, prev, next) { + if(unlikely(mp->pid == pid)) break; - } } - if (mp == NULL) + if(mp) { + DOUBLE_LINKED_LIST_REMOVE_UNSAFE(netdata_popen_root, mp, prev, next); + freez(mp); + } + else error("Cannot find pid %d.", pid); - netdata_mutex_unlock(&myp_lock); + netdata_mutex_unlock(&netdata_popen_tracking_mutex); } -#define PIPE_READ 0 -#define PIPE_WRITE 1 +// netdata_popen_tracking_init() should be called by apps which act as init +// (pid 1) so that processes created by mypopen and mypopene +// are tracked. This enables the reaper to ignore processes +// which will be handled internally, by calling myp_reap, to +// avoid issues with already reaped processes during wait calls. +// +// Callers should call myp_free() to clean up resources. +void netdata_popen_tracking_init(void) { + info("process tracking enabled."); + netdata_popen_tracking_enabled = true; + + if (netdata_mutex_init(&netdata_popen_tracking_mutex) != 0) + fatal("netdata_popen_tracking_init() mutex init failed."); +} + +// myp_free cleans up any resources allocated for process +// tracking. +void netdata_popen_tracking_cleanup(void) { + if(!netdata_popen_tracking_enabled) + return; + + netdata_mutex_lock(&netdata_popen_tracking_mutex); + netdata_popen_tracking_enabled = false; + + while(netdata_popen_root) { + struct netdata_popen *mp = netdata_popen_root; + DOUBLE_LINKED_LIST_REMOVE_UNSAFE(netdata_popen_root, mp, prev, next); + freez(mp); + } + + netdata_mutex_unlock(&netdata_popen_tracking_mutex); +} + +// myp_reap returns 1 if pid should be reaped, 0 otherwise. +int netdata_popen_tracking_pid_shoud_be_reaped(pid_t pid) { + if(!netdata_popen_tracking_enabled) + return 0; + + netdata_mutex_lock(&netdata_popen_tracking_mutex); + + int ret = 1; + struct netdata_popen *mp; + DOUBLE_LINKED_LIST_FOREACH_FORWARD(netdata_popen_root, mp, prev, next) { + if(unlikely(mp->pid == pid)) { + ret = 0; + break; + } + } + + netdata_mutex_unlock(&netdata_popen_tracking_mutex); + return ret; +} + +// ---------------------------------------------------------------------------- +// helpers static inline void convert_argv_to_string(char *dst, size_t size, const char *spawn_argv[]) { int i; @@ -89,118 +137,185 @@ static inline void convert_argv_to_string(char *dst, size_t size, const char *sp } } +// ---------------------------------------------------------------------------- +// the core of netdata popen + /* * Returns -1 on failure, 0 on success. When POPEN_FLAG_CREATE_PIPE is set, on success set the FILE *fp pointer. */ -static int custom_popene(volatile pid_t *pidptr, char **env, uint8_t flags, FILE **fpp, const char *command, const char *spawn_argv[]) { +#define PIPE_READ 0 +#define PIPE_WRITE 1 + +static int popene_internal(volatile pid_t *pidptr, char **env, uint8_t flags, FILE **fpp_child_stdin, FILE **fpp_child_stdout, const char *command, const char *spawn_argv[]) { // create a string to be logged about the command we are running char command_to_be_logged[2048]; convert_argv_to_string(command_to_be_logged, sizeof(command_to_be_logged), spawn_argv); // info("custom_popene() running command: %s", command_to_be_logged); - FILE *fp = NULL; - int ret = 0; // success by default - int pipefd[2], error; + int ret = 0; // success by default + int attr_rc = 1; // failure by default + + FILE *fp_child_stdin = NULL, *fp_child_stdout = NULL; + int pipefd_stdin[2] = { -1, -1 }; + int pipefd_stdout[2] = { -1, -1 }; + pid_t pid; posix_spawnattr_t attr; posix_spawn_file_actions_t fa; - if (flags & POPEN_FLAG_CREATE_PIPE) { - if (pipe(pipefd) == -1) - return -1; - if ((fp = fdopen(pipefd[PIPE_READ], "r")) == NULL) { - goto error_after_pipe; + int stdin_fd_to_exclude_from_closing = -1; + int stdout_fd_to_exclude_from_closing = -1; + + if(posix_spawn_file_actions_init(&fa)) { + error("POPEN: posix_spawn_file_actions_init() failed."); + return -1; + } + + if(fpp_child_stdin) { + if (pipe(pipefd_stdin) == -1) { + error("POPEN: stdin pipe() failed"); + ret = -1; + goto cleanup_and_return; + } + + if ((fp_child_stdin = fdopen(pipefd_stdin[PIPE_WRITE], "w")) == NULL) { + error("POPEN: fdopen() stdin failed"); + ret = -1; + goto cleanup_and_return; + } + + if(posix_spawn_file_actions_adddup2(&fa, pipefd_stdin[PIPE_READ], STDIN_FILENO)) { + error("POPEN: posix_spawn_file_actions_adddup2() on stdin failed."); + ret = -1; + goto cleanup_and_return; + } + } + else { + if (posix_spawn_file_actions_addopen(&fa, STDIN_FILENO, "/dev/null", O_RDONLY, 0)) { + error("POPEN: posix_spawn_file_actions_addopen() on stdin to /dev/null failed."); + // this is not a fatal error + stdin_fd_to_exclude_from_closing = STDIN_FILENO; } } - if (flags & POPEN_FLAG_CLOSE_FD) { - // Mark all files to be closed by the exec() stage of posix_spawn() - int i; - for (i = (int) (sysconf(_SC_OPEN_MAX) - 1); i >= 0; i--) { - if (i != STDIN_FILENO && i != STDERR_FILENO) - (void) fcntl(i, F_SETFD, FD_CLOEXEC); + if (fpp_child_stdout) { + if (pipe(pipefd_stdout) == -1) { + error("POPEN: stdout pipe() failed"); + ret = -1; + goto cleanup_and_return; + } + + if ((fp_child_stdout = fdopen(pipefd_stdout[PIPE_READ], "r")) == NULL) { + error("POPEN: fdopen() stdout failed"); + ret = -1; + goto cleanup_and_return; + } + + if(posix_spawn_file_actions_adddup2(&fa, pipefd_stdout[PIPE_WRITE], STDOUT_FILENO)) { + error("POPEN: posix_spawn_file_actions_adddup2() on stdout failed."); + ret = -1; + goto cleanup_and_return; + } + } + else { + if (posix_spawn_file_actions_addopen(&fa, STDOUT_FILENO, "/dev/null", O_WRONLY, 0)) { + error("POPEN: posix_spawn_file_actions_addopen() on stdout to /dev/null failed."); + // this is not a fatal error + stdout_fd_to_exclude_from_closing = STDOUT_FILENO; } } - if (!posix_spawn_file_actions_init(&fa)) { - if (flags & POPEN_FLAG_CREATE_PIPE) { - // move the pipe to stdout in the child - if (posix_spawn_file_actions_adddup2(&fa, pipefd[PIPE_WRITE], STDOUT_FILENO)) { - error("posix_spawn_file_actions_adddup2() failed"); - goto error_after_posix_spawn_file_actions_init; - } - } else { - // set stdout to /dev/null - if (posix_spawn_file_actions_addopen(&fa, STDOUT_FILENO, "/dev/null", O_WRONLY, 0)) { - error("posix_spawn_file_actions_addopen() failed"); - // this is not a fatal error - } + if(flags & POPEN_FLAG_CLOSE_FD) { + // Mark all files to be closed by the exec() stage of posix_spawn() + for(int i = (int)(sysconf(_SC_OPEN_MAX) - 1); i >= 0; i--) { + if(likely(i != STDERR_FILENO && i != stdin_fd_to_exclude_from_closing && i != stdout_fd_to_exclude_from_closing)) + (void)fcntl(i, F_SETFD, FD_CLOEXEC); } - } else { - error("posix_spawn_file_actions_init() failed."); - goto error_after_pipe; } - if (!(error = posix_spawnattr_init(&attr))) { + + attr_rc = posix_spawnattr_init(&attr); + if(attr_rc) { + // failed + error("POPEN: posix_spawnattr_init() failed."); + } + else { + // success // reset all signals in the child - sigset_t mask; if (posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF)) - error("posix_spawnattr_setflags() failed."); + error("POPEN: posix_spawnattr_setflags() failed."); + + sigset_t mask; sigemptyset(&mask); + if (posix_spawnattr_setsigmask(&attr, &mask)) - error("posix_spawnattr_setsigmask() failed."); - } else { - error("posix_spawnattr_init() failed."); + error("POPEN: posix_spawnattr_setsigmask() failed."); } // Take the lock while we fork to ensure we don't race with SIGCHLD // delivery on a process which exits quickly. - myp_add_lock(); + netdata_popen_tracking_lock(); if (!posix_spawn(&pid, command, &fa, &attr, (char * const*)spawn_argv, env)) { + // success *pidptr = pid; - myp_add_locked(pid); - debug(D_CHILDS, "Spawned command: \"%s\" on pid %d from parent pid %d.", command_to_be_logged, pid, getpid()); - } else { - myp_add_unlock(); - error("Failed to spawn command: \"%s\" from parent pid %d.", command_to_be_logged, getpid()); - if (flags & POPEN_FLAG_CREATE_PIPE) { - fclose(fp); - } - ret = -1; + netdata_popen_tracking_add_pid_unsafe(pid); + netdata_popen_tracking_unlock(); } - if (flags & POPEN_FLAG_CREATE_PIPE) { - close(pipefd[PIPE_WRITE]); - if (0 == ret) // on success set FILE * pointer - if(fpp) *fpp = fp; + else { + // failure + netdata_popen_tracking_unlock(); + error("POPEN: failed to spawn command: \"%s\" from parent pid %d.", command_to_be_logged, getpid()); + ret = -1; + goto cleanup_and_return; } - if (!error) { + // the normal cleanup will run + // but ret == 0 at this point + +cleanup_and_return: + if(!attr_rc) { // posix_spawnattr_init() succeeded if (posix_spawnattr_destroy(&attr)) - error("posix_spawnattr_destroy"); + error("POPEN: posix_spawnattr_destroy() failed"); } - if (posix_spawn_file_actions_destroy(&fa)) - error("posix_spawn_file_actions_destroy"); - return ret; - -error_after_posix_spawn_file_actions_init: if (posix_spawn_file_actions_destroy(&fa)) - error("posix_spawn_file_actions_destroy"); + error("POPEN: posix_spawn_file_actions_destroy() failed"); + + // the child end - close it + if(pipefd_stdin[PIPE_READ] != -1) + close(pipefd_stdin[PIPE_READ]); + + // our end + if(ret == -1 || !fpp_child_stdin) { + if (fp_child_stdin) + fclose(fp_child_stdin); + else if (pipefd_stdin[PIPE_WRITE] != -1) + close(pipefd_stdin[PIPE_WRITE]); + } + else { + *fpp_child_stdin = fp_child_stdin; + } -error_after_pipe: - if (flags & POPEN_FLAG_CREATE_PIPE) { - if (fp) - fclose(fp); - else - close(pipefd[PIPE_READ]); + // the child end - close it + if (pipefd_stdout[PIPE_WRITE] != -1) + close(pipefd_stdout[PIPE_WRITE]); - close(pipefd[PIPE_WRITE]); + // our end + if (ret == -1 || !fpp_child_stdout) { + if (fp_child_stdout) + fclose(fp_child_stdout); + else if (pipefd_stdout[PIPE_READ] != -1) + close(pipefd_stdout[PIPE_READ]); } - return -1; + else { + *fpp_child_stdout = fp_child_stdout; + } + + return ret; } -int custom_popene_variadic_internal_dont_use_directly(volatile pid_t *pidptr, char **env, uint8_t flags, FILE **fpp, const char *command, ...) { +int netdata_popene_variadic_internal_dont_use_directly(volatile pid_t *pidptr, char **env, uint8_t flags, FILE **fpp_child_input, FILE **fpp_child_output, const char *command, ...) { // convert the variable list arguments into what posix_spawn() needs // all arguments are expected strings va_list args; @@ -232,88 +347,34 @@ int custom_popene_variadic_internal_dont_use_directly(volatile pid_t *pidptr, ch va_end(args); } - return custom_popene(pidptr, env, flags, fpp, command, spawn_argv); + return popene_internal(pidptr, env, flags, fpp_child_input, fpp_child_output, command, spawn_argv); } // See man environ extern char **environ; -// myp_init should be called by apps which act as init -// (pid 1) so that processes created by mypopen and mypopene -// are tracked. This enables the reaper to ignore processes -// which will be handled internally, by calling myp_reap, to -// avoid issues with already reaped processes during wait calls. -// -// Callers should call myp_free() to clean up resources. -void myp_init(void) { - info("process tracking enabled."); - myp_tracking = 1; - - if (netdata_mutex_init(&myp_lock) != 0) { - fatal("myp_init() mutex init failed."); - } -} - -// myp_free cleans up any resources allocated for process -// tracking. -void myp_free(void) { - struct mypopen *mp, *next; - - if (myp_tracking == 0) - return; - - netdata_mutex_lock(&myp_lock); - for (mp = mypopen_root; mp != NULL; mp = next) { - next = mp->next; - freez(mp); - } - - mypopen_root = NULL; - myp_tracking = 0; - netdata_mutex_unlock(&myp_lock); -} - -// myp_reap returns 1 if pid should be reaped, 0 otherwise. -int myp_reap(pid_t pid) { - struct mypopen *mp; - - if (myp_tracking == 0) - return 0; - - netdata_mutex_lock(&myp_lock); - for (mp = mypopen_root; mp != NULL; mp = mp->next) { - if (mp->pid == pid) { - netdata_mutex_unlock(&myp_lock); - return 0; - } - } - netdata_mutex_unlock(&myp_lock); - - return 1; -} - -FILE *mypopen(const char *command, volatile pid_t *pidptr) { - FILE *fp = NULL; +FILE *netdata_popen(const char *command, volatile pid_t *pidptr, FILE **fpp_child_input) { + FILE *fp_child_output = NULL; const char *spawn_argv[] = { "sh", "-c", command, NULL }; - (void)custom_popene(pidptr, environ, POPEN_FLAG_CREATE_PIPE|POPEN_FLAG_CLOSE_FD, &fp, "/bin/sh", spawn_argv); - return fp; + (void)popene_internal(pidptr, environ, POPEN_FLAG_CLOSE_FD, fpp_child_input, &fp_child_output, "/bin/sh", spawn_argv); + return fp_child_output; } -FILE *mypopene(const char *command, volatile pid_t *pidptr, char **env) { - FILE *fp = NULL; +FILE *netdata_popene(const char *command, volatile pid_t *pidptr, char **env, FILE **fpp_child_input) { + FILE *fp_child_output = NULL; const char *spawn_argv[] = { "sh", "-c", command, NULL }; - (void)custom_popene( pidptr, env, POPEN_FLAG_CREATE_PIPE|POPEN_FLAG_CLOSE_FD, &fp, "/bin/sh", spawn_argv); - return fp; + (void)popene_internal(pidptr, env, POPEN_FLAG_CLOSE_FD, fpp_child_input, &fp_child_output, "/bin/sh", spawn_argv); + return fp_child_output; } // returns 0 on success, -1 on failure @@ -324,29 +385,25 @@ int netdata_spawn(const char *command, volatile pid_t *pidptr) { command, NULL }; - return custom_popene( pidptr, environ, POPEN_FLAG_NONE, NULL, "/bin/sh", spawn_argv); + return popene_internal(pidptr, environ, POPEN_FLAG_NONE, NULL, NULL, "/bin/sh", spawn_argv); } -int custom_pclose(FILE *fp, pid_t pid) { +int netdata_pclose(FILE *fp_child_input, FILE *fp_child_output, pid_t pid) { int ret; siginfo_t info; - debug(D_EXIT, "Request to mypclose() on pid %d", pid); + debug(D_EXIT, "Request to netdata_pclose() on pid %d", pid); - if (fp) { - // close the pipe fd - // this is required in musl - // without it the childs do not exit - close(fileno(fp)); + if (fp_child_input) + fclose(fp_child_input); - // close the pipe file pointer - fclose(fp); - } + if (fp_child_output) + fclose(fp_child_output); errno = 0; ret = waitid(P_PID, (id_t) pid, &info, WEXITED); - myp_del(pid); + netdata_popen_tracking_del_pid(pid); if (ret != -1) { switch (info.si_code) { @@ -392,12 +449,6 @@ int custom_pclose(FILE *fp, pid_t pid) { return 0; } -int mypclose(FILE *fp, pid_t pid) -{ - return custom_pclose(fp, pid); -} - -int netdata_spawn_waitpid(pid_t pid) -{ - return custom_pclose(NULL, pid); +int netdata_spawn_waitpid(pid_t pid) { + return netdata_pclose(NULL, NULL, pid); } diff --git a/libnetdata/popen/popen.h b/libnetdata/popen/popen.h index 57eb9131e0..a0cf5f101f 100644 --- a/libnetdata/popen/popen.h +++ b/libnetdata/popen/popen.h @@ -10,29 +10,29 @@ /* custom_popene_variadic_internal_dont_use_directly flag definitions */ #define POPEN_FLAG_NONE 0 -#define POPEN_FLAG_CREATE_PIPE 1 // Create a pipe like popen() when set, otherwise set stdout to /dev/null -#define POPEN_FLAG_CLOSE_FD 2 // Close all file descriptors other than STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO +#define POPEN_FLAG_CLOSE_FD (1 << 0) // Close all file descriptors other than STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO // the flags to be used by default -#define POPEN_FLAGS_DEFAULT (POPEN_FLAG_CREATE_PIPE|POPEN_FLAG_CLOSE_FD) +#define POPEN_FLAGS_DEFAULT (POPEN_FLAG_CLOSE_FD) // mypopen_raw is the interface to use instead of custom_popene_variadic_internal_dont_use_directly() // mypopen_raw will add the terminating NULL at the arguments list // we append the parameter 'command' twice - this is because the underlying call needs the command to execute and the argv[0] to pass to it -#define mypopen_raw_default_flags_and_environment(pidptr, fpp, command, args...) custom_popene_variadic_internal_dont_use_directly(pidptr, environ, POPEN_FLAGS_DEFAULT, fpp, command, command, ##args, NULL) -#define mypopen_raw_default_flags(pidptr, env, fpp, command, args...) custom_popene_variadic_internal_dont_use_directly(pidptr, env, POPEN_FLAGS_DEFAULT, fpp, command, command, ##args, NULL) -#define mypopen_raw(pidptr, env, flags, fpp, command, args...) custom_popene_variadic_internal_dont_use_directly(pidptr, env, flags, fpp, command, command, ##args, NULL) +#define netdata_popen_raw_default_flags_and_environment(pidptr, fpp_child_input, fpp_child_output, command, args...) netdata_popene_variadic_internal_dont_use_directly(pidptr, environ, POPEN_FLAGS_DEFAULT, fpp_child_input, fpp_child_output, command, command, ##args, NULL) +#define netdata_popen_raw_default_flags(pidptr, env, fpp_child_input, fpp_child_output, command, args...) netdata_popene_variadic_internal_dont_use_directly(pidptr, env, POPEN_FLAGS_DEFAULT, fpp_child_input, fpp_child_output, command, command, ##args, NULL) +#define netdata_popen_raw(pidptr, env, flags, fpp_child_input, fpp_child_output, command, args...) netdata_popene_variadic_internal_dont_use_directly(pidptr, env, flags, fpp_child_input, fpp_child_output, command, command, ##args, NULL) -extern int custom_popene_variadic_internal_dont_use_directly(volatile pid_t *pidptr, char **env, uint8_t flags, FILE **fpp, const char *command, ...); +extern FILE *netdata_popen(const char *command, volatile pid_t *pidptr, FILE **fp_child_input); +extern FILE *netdata_popene(const char *command, volatile pid_t *pidptr, char **env, FILE **fp_child_input); +extern int netdata_popene_variadic_internal_dont_use_directly(volatile pid_t *pidptr, char **env, uint8_t flags, FILE **fpp_child_input, FILE **fpp_child_output, const char *command, ...); +extern int netdata_pclose(FILE *fp_child_input, FILE *fp_child_output, pid_t pid); -extern FILE *mypopen(const char *command, volatile pid_t *pidptr); -extern FILE *mypopene(const char *command, volatile pid_t *pidptr, char **env); -extern int mypclose(FILE *fp, pid_t pid); extern int netdata_spawn(const char *command, volatile pid_t *pidptr); extern int netdata_spawn_waitpid(pid_t pid); -extern void myp_init(void); -extern void myp_free(void); -extern int myp_reap(pid_t pid); + +extern void netdata_popen_tracking_init(void); +extern void netdata_popen_tracking_cleanup(void); +extern int netdata_popen_tracking_pid_shoud_be_reaped(pid_t pid); extern void signals_unblock(void); extern void signals_reset(void); |