Files
spine/util.h
T
86a062dd09 ci: enforce cross-platform quality gates and connector coverage (#618)
## Summary

Consolidates the connector/build work from #613 and the broader
test-infrastructure work extracted from #597 into one review:

- discover MariaDB Connector/C first while retaining MySQL and
Percona-compatible support
- test MariaDB and MySQL Connector/C with strict GCC and Clang builds on
Ubuntu 24.04
- add a real macOS 15 build and unit-test lane with portable Autotools
platform detection
- run unit tests under ASan/UBSan and ThreadSanitizer
- enforce the measured 7% global coverage baseline and 70% changed-line
coverage
- add libFuzzer coverage for output parsing alongside the existing
hostname parser
- exercise the SNMPv3 integration suite against MariaDB and MySQL 8.4
- add cppcheck, shellcheck, DCO verification, CODEOWNERS, distcheck, and
Linux-capability checks while retaining the repository-managed default
CodeQL setup
- expose a stable `CI / required` aggregate check for branch protection
- pin runners and third-party actions and keep workflow permissions
read-only by default

## Correctness fixes found by the new gates

- reject truncated capability strings and poller-output SQL tuples
instead of publishing partial data
- make `bootstrap` fail closed and select `libtoolize`/`glibtoolize`
portably
- use Autoconf's canonical host for Darwin detection instead of an empty
native-build alias
- remove stale initialization/name-shadow findings and make read-only
interfaces const-correct
- make the ICMP parser test portable across Linux and BSD header names

## Verification

- strict GCC and Clang builds: 4/4 unit targets passed
- ASan/UBSan: 4/4 passed
- ThreadSanitizer: 4/4 passed
- macOS Clang/Homebrew build: 4/4 passed
- MariaDB integration: passed
- MySQL 8.4 integration: passed
- both libFuzzer targets: passed sustained local runs
- coverage: 7.2% global and 84% on changed lines
- cppcheck, shellcheck, actionlint, DCO verification, and `git diff
--check`: passed locally

## Post-merge repository settings

After these workflows exist on `develop`, an administrator should
require `CI / required`, Fuzz, Integration, Rocky Linux, and the
repository-managed CodeQL/code-scanning result in the active ruleset;
enable code-owner approval; and require the branch to be current (or use
a merge queue). Enabling those settings before this PR merges would
create required checks that the base branch cannot yet emit.

Consolidates and supersedes #613. Closes #612.

---------

Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Signed-off-by: TheWitness <thewitness@cacti.net>
Signed-off-by: TheWitness <copilot@users.noreply.github.com>
Co-authored-by: TheWitness <thewitness@cacti.net>
Co-authored-by: TheWitness <copilot@users.noreply.github.com>
2026-09-24 05:52:56 -04:00

139 lines
6.0 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);
/* 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_numeric(char *string);
extern int is_ipaddress(const char *string);
extern int all_digits(const char *str);
extern int is_hexadecimal(const char * str, const short ignore_special);
/* determine if a device is a debug device */
extern int is_debug_device(int device_id);
/* 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 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);
/* convert a delimited hexadecimal value without conflating overflow with 0 */
int hex2dec(const char *str, unsigned long long *result);
/* 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
const char *regex_replace(const char *exp, const 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 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);
/*! \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 */