mirror of
https://github.com/Cacti/spine.git
synced 2026-10-23 03:27:10 +09:00
The runtime/probe changes from #642 and GNU C17/build changes from #643 were squash-merged into #641's source branch, which made the result-normalization review include later stages. This follow-up preserves those approved changes while restoring #641's focused diff against develop. No force-push or approved-code deletion is required. Merge after #641 and before #644. #644 will target this branch. This combines the already reviewed steps 5 and 6; it introduces no new worker-stack or module-extraction changes. The UDP follow-up also corrects a validated finding: EHOSTUNREACH on a connected socket is ambiguous and can represent an unreachable host or failed neighbour lookup. It now reports down; ECONNREFUSED/ECONNRESET and actual peer datagrams retain their existing alive behavior. The production-linked test rejects the original EHOSTUNREACH behavior. Validation: Ubuntu 24.04/aarch64, clean GCC build and make check: 17 passed, one existing setuid prerequisite skip, zero failures. The full tracked source tree is byte-identical to the independently validated #641 functional-fix snapshot. The UDP and poll-host regressions fail against the original code and pass after the fixes. The isolated step-4 tree independently passes 15 tests with one existing skip. No live endpoints, host installation, privilege changes, or test suppression. Repository squash merges still require restacking/retargeting the next child after each merge; clean ordinary merge simulations are insufficient by themselves. --------- Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
201 lines
8.6 KiB
C
201 lines
8.6 KiB
C
/*
|
|
ex: set tabstop=4 shiftwidth=4 autoindent:*
|
|
+-------------------------------------------------------------------------+
|
|
| Copyright (C) 2004-2026 The Cacti Group |
|
|
| |
|
|
| This program is free software; you can redistribute it and/or |
|
|
| modify it under the terms of the GNU Lesser General Public |
|
|
| License as published by the Free Software Foundation; either |
|
|
| version 2.1 of the License, or (at your option) any later version. |
|
|
| |
|
|
| This program is distributed in the hope that it will be useful, |
|
|
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
| GNU Lesser General Public License for more details. |
|
|
| |
|
|
| You should have received a copy of the GNU Lesser General Public |
|
|
| License along with this library; if not, write to the Free Software |
|
|
| Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
|
|
| 02110-1301, USA |
|
|
| |
|
|
+-------------------------------------------------------------------------+
|
|
| spine: a backend data gatherer for cacti |
|
|
+-------------------------------------------------------------------------+
|
|
| This poller would not have been possible without: |
|
|
| - Larry Adams (current development and enhancements) |
|
|
| - Rivo Nurges (rrd support, mysql poller cache, misc functions) |
|
|
| - RTG (core poller code, pthreads, snmp, autoconf examples) |
|
|
| - Brady Alleman/Doug Warner (threading ideas, implementation details) |
|
|
+-------------------------------------------------------------------------+
|
|
| - Cacti - http://www.cacti.net/ |
|
|
+-------------------------------------------------------------------------+
|
|
*/
|
|
|
|
#ifndef SPINE_UTIL_H
|
|
#define SPINE_UTIL_H
|
|
/* cacti config reading functions */
|
|
extern void read_config_options(void);
|
|
extern int read_spine_config(const char *file);
|
|
extern void config_defaults(void);
|
|
extern bool poller_transfer_status(MYSQL *source, MYSQL *destination);
|
|
extern void poller_push_data_to_main(void);
|
|
|
|
/* cacti logging function */
|
|
extern int spine_log(const char *format, ...)
|
|
__attribute__((format(printf, 1, 2)));
|
|
|
|
extern void die(const char *format, ...)
|
|
__attribute__((noreturn))
|
|
__attribute__((format(printf, 1, 2)));
|
|
|
|
/* option processing function */
|
|
extern void set_option(const char *setting, const char *value);
|
|
|
|
/* number validation functions */
|
|
extern int is_ipaddress(const char *string);
|
|
extern int all_digits(const char *str);
|
|
|
|
/* what a poll returned; text is what poller_output stores, U if unknown */
|
|
typedef enum {
|
|
RESULT_UNKNOWN = 0,
|
|
RESULT_COUNTER,
|
|
RESULT_SIGNED,
|
|
RESULT_FLOAT,
|
|
RESULT_HEX_COUNTER,
|
|
RESULT_MULTIPART
|
|
} result_kind_t;
|
|
|
|
typedef struct {
|
|
result_kind_t kind;
|
|
union {
|
|
uint64_t counter;
|
|
int64_t integer;
|
|
double real;
|
|
} value;
|
|
char text[RESULTS_BUFFER];
|
|
} classified_result_t;
|
|
|
|
extern result_kind_t classify_result(const char *raw, classified_result_t *out);
|
|
|
|
/* determine if a device is a debug device */
|
|
extern int is_debug_device(int device_id);
|
|
extern void parse_debug_devices(char *device_list, int *devices, size_t capacity);
|
|
extern bool spine_should_log_device(int host_id, int verbosity);
|
|
|
|
/* string and file functions */
|
|
extern char *add_slashes(const char *string);
|
|
extern int file_exists(const char *filename);
|
|
extern char *strip_alpha(char *string);
|
|
extern char *strncopy(char *dst, const char *src, size_t n);
|
|
extern int spine_snprintf(char *output, size_t capacity, const char *format, ...)
|
|
__attribute__((format(printf, 3, 4)));
|
|
extern void spine_clear_sensitive(void *buffer, size_t length);
|
|
extern void spine_sanitize_log_message(char *message);
|
|
extern char *trim(char *str);
|
|
extern char *rtrim(char *str);
|
|
extern char *ltrim(char *str);
|
|
extern char *reverse(char *str);
|
|
extern int strpos(const char *haystack, const char *needle) ;
|
|
extern int char_count(const char *str, int chr);
|
|
|
|
/* custom regex replace to return a value if matches */
|
|
#define MAX_MATCHES 5
|
|
#define REGEX_NUMBER "([-+]*)([0-9]*)([.][0-9]+)"
|
|
#define CAPABILITY_PROTOCOL_LIST_MAX 480
|
|
char *regex_replace(const char *exp, char *value);
|
|
int format_spine_capabilities(char *output, size_t output_size,
|
|
const char *auth_protocols, const char *priv_protocols);
|
|
|
|
/* macro to copy string to string with an ending null */
|
|
#define STRNCOPY(dst, src) strncopy((dst), (src), sizeof(dst))
|
|
#define USTRNCOPY(dst, src) ustrncopy((dst), (src), sizeof(dst))
|
|
|
|
/* macro to duplicate string and die if fails */
|
|
#define STRDUP_OR_DIE(dst, src, reason) \
|
|
if ((dst = strdup(src)) == NULL) {\
|
|
die("FATAL: malloc() failed during strdup() for %s", reason);\
|
|
}\
|
|
|
|
|
|
/* get highres time as double */
|
|
extern double get_time_as_double(void);
|
|
|
|
/* function to check to see if program has capability to use raw socket with
|
|
out uid = 0 */
|
|
extern void drop_privileges(void);
|
|
extern int privileges_dropped(uid_t uid, gid_t gid);
|
|
extern int hasCaps(void);
|
|
|
|
/* see if we can do things as root */
|
|
extern void checkAsRoot(void);
|
|
|
|
/* log format */
|
|
extern void set_date_format(void);
|
|
extern char *get_date_format(void);
|
|
|
|
/* remote/main server synchronization */
|
|
extern void poller_push_data_to_main(void);
|
|
|
|
/* MySQL supports INSERT row aliases from 8.0.20; MariaDB does not. */
|
|
extern int db_row_alias_upsert_supported(const char *version, unsigned long version_number);
|
|
|
|
/* start time for spine */
|
|
extern double start_time;
|
|
|
|
/* the version of Cacti as a decimal */
|
|
int get_cacti_version(MYSQL *psql, int mode);
|
|
|
|
extern void spine_sleep_usec(unsigned int microseconds);
|
|
extern double spine_monotonic_time(void);
|
|
|
|
extern int spine_count_to_int(unsigned long long count);
|
|
|
|
extern int spine_wait_readable(int fd, double deadline);
|
|
extern int spine_wait_writable(int fd, double deadline);
|
|
|
|
extern int spine_permits_init(spine_permits_t *permits, int count);
|
|
extern int spine_permits_destroy(spine_permits_t *permits);
|
|
extern int spine_permits_try_acquire(spine_permits_t *permits);
|
|
extern int spine_permits_release(spine_permits_t *permits);
|
|
extern int spine_permits_available(spine_permits_t *permits);
|
|
|
|
/* Stack for every thread spine creates. The deepest worker path, child()
|
|
* through poll_host() into the SNMP, script, ping and logging code, peaked at
|
|
* 179,024 bytes (glibc, gcc ASan, live MariaDB and snmpd) and sums to 175,856
|
|
* bytes statically (gcc 15 -fcallgraph-info=su on musl). About five results
|
|
* buffers of that grow with --with-results-buffer. musl's 128 KiB default
|
|
* overflows on entry to poll_host(). Reserve twice 180 KiB plus five results
|
|
* buffers, rounded up to 64 KiB so the size is a page multiple everywhere:
|
|
* 384 KiB with the default 2048-byte results buffer. */
|
|
/* Check the unrounded expression before evaluating its size_t arithmetic. */
|
|
_Static_assert(RESULTS_BUFFER >= 2, "RESULTS_BUFFER must hold a value and terminator");
|
|
_Static_assert((size_t) RESULTS_BUFFER <= (SIZE_MAX - ((size_t) 2 * 180 * 1024 + 65535)) / 10,
|
|
"RESULTS_BUFFER overflows the worker stack size");
|
|
#define SPINE_THREAD_STACK_SIZE \
|
|
(((size_t) 2 * ((size_t) 180 * 1024 + 5 * (size_t) RESULTS_BUFFER) + 65535) & ~(size_t) 65535)
|
|
|
|
/*! \fn int spine_thread_attr_init(pthread_attr_t *attributes)
|
|
* \brief initialize thread attributes with at least SPINE_THREAD_STACK_SIZE
|
|
* \return 0, or the pthread error; on error nothing is left to destroy
|
|
*/
|
|
extern int spine_thread_attr_init(pthread_attr_t *attributes);
|
|
|
|
/*! \fn int spine_appendf(char **cursor, size_t *remaining, const char *fmt, ...)
|
|
* \brief append to a bounded buffer without walking off the end
|
|
*
|
|
* snprintf() returns the length it would have written, so `p += snprintf(p,
|
|
* remaining, ...)` moves the cursor past the buffer the first time a value is
|
|
* truncated. The next `remaining` is then negative, and as a size_t it is
|
|
* effectively unbounded, at a destination already out of bounds.
|
|
*
|
|
* This advances the cursor by what was actually written, stops on the
|
|
* terminator when the text does not fit, and says so.
|
|
*
|
|
* \return TRUE when the whole string was appended, FALSE on truncation or a
|
|
* formatting error, in which case the buffer stays NUL-terminated
|
|
*/
|
|
extern int spine_appendf(char **cursor, size_t *remaining, const char *fmt, ...)
|
|
__attribute__((format(printf, 3, 4)));
|
|
|
|
#endif /* SPINE_UTIL_H */
|