mirror of
https://github.com/clearlinux/telemetrics-client.git
synced 2026-09-01 11:15:51 +00:00
Compare commits
33
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f5114e9b36 | ||
|
|
03fbd65fbd | ||
|
|
d1f11980be | ||
|
|
d75e27a5c4 | ||
|
|
9baf5f821e | ||
|
|
be98da141d | ||
|
|
55bb762479 | ||
|
|
be78434f2c | ||
|
|
8edd75df21 | ||
|
|
dc4f4e67e4 | ||
|
|
41e9090dd8 | ||
|
|
cbcc5e24d5 | ||
|
|
4a9d8212c8 | ||
|
|
8a9dbc7528 | ||
|
|
da45642759 | ||
|
|
ed1c85a481 | ||
|
|
b4ac36f7a6 | ||
|
|
2f07fd658c | ||
|
|
4b10dbec86 | ||
|
|
bc3c7b6a4d | ||
|
|
15d32841f0 | ||
|
|
e3178e1624 | ||
|
|
7de4351f16 | ||
|
|
73adb8981a | ||
|
|
5ead074c89 | ||
|
|
80292b5bf8 | ||
|
|
1517ff4c18 | ||
|
|
85772cb5c5 | ||
|
|
d75fa6fda2 | ||
|
|
6c7c5be2e2 | ||
|
|
913cbb1c1e | ||
|
|
d3ce2f435c | ||
|
|
d0a3e6bafa |
@@ -38,6 +38,7 @@ autoscan.log
|
||||
configure.scan
|
||||
tprobe
|
||||
hprobe
|
||||
bertprobe
|
||||
crashprobe
|
||||
journalprobe
|
||||
telem-record-gen
|
||||
@@ -45,6 +46,7 @@ klogscanner
|
||||
oopsprobe
|
||||
pstoreclean
|
||||
pstoreprobe
|
||||
telem_journal
|
||||
make.out
|
||||
types_c.taghl
|
||||
src/recomp.sh
|
||||
|
||||
+3
-3
@@ -25,9 +25,9 @@ addons:
|
||||
- libdw-dev
|
||||
|
||||
install:
|
||||
- wget http://downloads.sourceforge.net/project/check/check/0.10.0/check-0.10.0.tar.gz
|
||||
- tar -xvf check-0.10.0.tar.gz
|
||||
- pushd check-0.10.0 && ./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu && make -j48 && sudo make install && popd
|
||||
- wget https://github.com/libcheck/check/releases/download/0.12.0/check-0.12.0.tar.gz
|
||||
- tar -xvf check-0.12.0.tar.gz
|
||||
- pushd check-0.12.0 && ./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu && make -j48 && sudo make install && popd
|
||||
|
||||
script:
|
||||
- ./configure && make && make check
|
||||
|
||||
@@ -20,6 +20,7 @@ include $(top_srcdir)/src/local.mk
|
||||
include $(top_srcdir)/src/data/local.mk
|
||||
include $(top_srcdir)/src/nica/local.mk
|
||||
include $(top_srcdir)/src/probes/local.mk
|
||||
include $(top_srcdir)/src/journal/local.mk
|
||||
include $(top_srcdir)/tests/local.mk
|
||||
|
||||
release:
|
||||
|
||||
@@ -15,6 +15,10 @@ component includes:
|
||||
(not included in this source tree), or spools the records on disk in case
|
||||
it's unable to successfully deliver them.
|
||||
|
||||
A telemetrics server implementation that works with this component is available
|
||||
from
|
||||
[clearlinux/telemetrics-backend](https://github.com/clearlinux/telemetrics-backend).
|
||||
|
||||
|
||||
Build dependencies
|
||||
---------------------
|
||||
@@ -162,6 +166,17 @@ The daemon uses the following configuration options from the configuration file:
|
||||
threshold has been reached. Currently the options are 'drop' or 'spool', with
|
||||
spool being the default. If spool is chosen, records will be spooled and sent
|
||||
at a later time.
|
||||
* record_retention_enabled: When this key is enabled (true) the daemon saves a
|
||||
copy of the payload on disk from all valid records. To avoid the excessive use
|
||||
of disk space only the latest 100 records are kept. The default value for this
|
||||
configuration key is false.
|
||||
* record_server_delivery_enabled: This key controls the delivery of records to
|
||||
```server```, when enabled (default value) the record will be posted to the
|
||||
address in the configuration file. If this configuration key is disabled (false)
|
||||
records will not be spooled or posted to backend. This configuration key can
|
||||
be used in combination with ```record_retention_enabled``` to keep copies of
|
||||
telemetry records locally only.
|
||||
|
||||
|
||||
Machine id
|
||||
---------------------
|
||||
@@ -190,3 +205,69 @@ You can switch back to the rotating machine id by deleting the override file
|
||||
and restarting the daemon. You can do a quick test to check that your
|
||||
machine-id has changed by running "hprobe" and verifying that a record has
|
||||
landed on your backend telemetrics server, with the specified machine id.
|
||||
|
||||
Event Id
|
||||
----------------------
|
||||
|
||||
This is a 32 character lowercase hexadecimal string i.e. '5de9de8d5f3c6a7d445d75ba01cc3322'.
|
||||
This header is used to group multiple records by an event id. Before this header
|
||||
every single record could have been thought of an event, however this is not always
|
||||
the case. There are "events" that trigger the creation of multiple records (i.e.
|
||||
updates). The ```event_id``` header was added for probes with the capability to
|
||||
detect events and group records based on such events. This header was added to
|
||||
```telem-record-gen``` and can be specified using the ```-e``` (```--event-id```
|
||||
long form) switch.
|
||||
|
||||
```{r, engine=bash, count_lines}
|
||||
-e, --event-id Event id to use in the record
|
||||
```
|
||||
|
||||
Debugging locally with telemetrics-client
|
||||
-----------------------------------------------
|
||||
|
||||
The function of the telemetrics-client is to handle the transport of information
|
||||
reported by a probe to a backend (see ```server``` key in configuration). This
|
||||
information is helpful for developers to debug and fix reported crashes, however
|
||||
developers not always have access to the backend in these case users can leverage
|
||||
features added for local debugging. The following is a list of steps to enable
|
||||
local debug:
|
||||
|
||||
* *Enabling record retention*: this step configures telemd to keep
|
||||
copies of telemetry records locally. To enable record retention set the value of
|
||||
```record_retention_enabled``` from ```false``` to ```true```. Optionally set
|
||||
```record_server_delivery_enabled`` to ```false``` to keep records local only.
|
||||
Remember to restart the daemon after configuration values are updated
|
||||
(```telemctl restart```).
|
||||
|
||||
* *Creating a record*: run ```hprobe``` command to create a record for the purposes
|
||||
of this step by step guide. Once we have the record or records that you need to
|
||||
capture locally you can display the data.
|
||||
|
||||
* *Displaying record metadata*: telemd keeps metadata of any valid record,
|
||||
to display this data a new option to telemctl was added ```telemctl journal```.
|
||||
Assuming that the last record created was the record from previous step `hprobe` we
|
||||
can use `tail -n 1` to print the last created record only, i.e.
|
||||
|
||||
```
|
||||
$ sudo telemctl journal | tail -n 1
|
||||
$ org.clearlinux/hello/world Mon 2018-04-02 17:48:01 UTC a19a0d41ba16788881e274b19b8a1be4 5de9de8d5f3c6a7d445d75ba01cc3322 60c014cd-4693-40f1-b334-548cd932949b
|
||||
```
|
||||
|
||||
The headers for the metadata (along with other information) can be printed using the
|
||||
```-V``` switch with ```telemctl journal``` command, i.e.
|
||||
|
||||
```
|
||||
$ sudo telemctl journal -V | head -n 1
|
||||
$ Classification Time stamp Record ID Event ID Boot ID
|
||||
```
|
||||
|
||||
* *Displaying record payload*: to print the content of a record payload you can use
|
||||
the ```-i``` (```--include_record``` long format) option to ```telemctl journal```
|
||||
command. To print the specific record you created you can use the option ```-r```
|
||||
(```--record_id``` long format) with the Record Id of the generated record, i.e.
|
||||
|
||||
```
|
||||
$ sudo telemctl journal --record_id a19a0d41ba16788881e274b19b8a1be4 --include_record
|
||||
$ org.clearlinux/hello/world Mon 2018-04-02 17:48:01 UTC a19a0d41ba16788881e274b19b8a1be4 5de9de8d5f3c6a7d445d75ba01cc3322 60c014cd-4693-40f1-b334-548cd932949b
|
||||
$ hello
|
||||
```
|
||||
|
||||
+6
-1
@@ -2,7 +2,7 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.69])
|
||||
AC_INIT([telemetrics-client], [1.13.0], [https://clearlinux.org/])
|
||||
AC_INIT([telemetrics-client], [1.16.0], [https://clearlinux.org/])
|
||||
AC_CONFIG_AUX_DIR([build-aux])
|
||||
AM_INIT_AUTOMAKE([1.14 -Wall -Werror -Wno-extra-portability foreign subdir-objects])
|
||||
AM_SILENT_RULES([yes])
|
||||
@@ -98,6 +98,11 @@ AC_ARG_WITH([systemdsysctldir], AS_HELP_STRING([--with-systemdsysctldir=DIR],
|
||||
test -z "${sysctlpath}" && sysctlpath=/usr/lib/sysctl.d
|
||||
AC_SUBST(SYSTEMD_SYSCTLDIR, [${sysctlpath}])
|
||||
|
||||
AC_ARG_WITH([systemdsystemctldir], AS_HELP_STRING([--with-systemdsystemctldir=DIR],
|
||||
[path to systemd systemctl dir @<:@default=/usr/bin@:>@]), [systemctlpath=${withval}])
|
||||
test -z "${systemctlpath}" && systemctlpath=/usr/bin
|
||||
AC_SUBST(SYSTEMD_SYSTEMCTLDIR, [${systemctlpath}])
|
||||
|
||||
# systemd.pc gives the /etc conf dir, so we can't use PKG_CONFIG for this one
|
||||
AC_ARG_WITH([systemdsystemconfdir], AS_HELP_STRING([--with-systemdsystemconfdir=DIR],
|
||||
[path to systemd system conf dir @<:@default=/usr/lib/systemd/system.conf.d@:>@]), [confpath=${withval}],
|
||||
|
||||
+40
-8
@@ -18,6 +18,17 @@ declare -a SERVICES=(
|
||||
SCRIPT="$0"
|
||||
TELEM_DIR=/etc/telemetrics
|
||||
OPT_OUT_FILE=${TELEM_DIR}/opt-out
|
||||
TELEM_WRK_DIRS_CONF=/usr/lib/tmpfiles.d/telemetrics-dirs.conf
|
||||
|
||||
create_work_dirs() {
|
||||
# Creates dirs if missing, adjust ownership if exists
|
||||
systemd-tmpfiles --create ${TELEM_WRK_DIRS_CONF}
|
||||
}
|
||||
|
||||
telem_remove_work_dirs() {
|
||||
# Remove dirs
|
||||
awk '/^d/{print $2}' ${TELEM_WRK_DIRS_CONF} | xargs rm -rf;
|
||||
}
|
||||
|
||||
exit_ok() {
|
||||
echo "$1" > /dev/stderr
|
||||
@@ -50,15 +61,23 @@ telem_stop() {
|
||||
|
||||
telem_start() {
|
||||
[ -f $OPT_OUT_FILE ] && exit_err "Opt out is enabled. Cannot start services."
|
||||
# trigger systemd-tmpfiles work dirs creation
|
||||
create_work_dirs
|
||||
# the units in SERVICES are activated as needed, so no need to start them
|
||||
for_each_service "start" ${SPECIAL_UNITS[@]}
|
||||
}
|
||||
|
||||
telem_is_active() {
|
||||
# check only activation units
|
||||
systemctl is-active telemd.socket
|
||||
}
|
||||
|
||||
telem_opt_out() {
|
||||
[ -f $OPT_OUT_FILE ] && exit_ok "Already opted out. Nothing to do."
|
||||
mkdir -p $TELEM_DIR || exit_err "Failed to create ${TELEM_DIR}."
|
||||
touch $OPT_OUT_FILE || exit_err "Failed to create ${OPT_OUT_FILE}."
|
||||
telem_stop
|
||||
telem_remove_work_dirs
|
||||
}
|
||||
|
||||
telem_opt_in() {
|
||||
@@ -72,20 +91,29 @@ telem_restart() {
|
||||
telem_start
|
||||
}
|
||||
|
||||
telem_journal_cli() {
|
||||
telem_journal "$@"
|
||||
}
|
||||
|
||||
usage() {
|
||||
printf "$SCRIPT - Control actions for telemetry services\n"
|
||||
format=' %-10s %s\n'
|
||||
printf "\n"
|
||||
printf "%15s %-65s\n" "stop" "Stops all running telemetry services"
|
||||
printf "%15s %-65s\n" "start" "Starts all telemetry services"
|
||||
printf "%15s %-65s\n" "restart" "Restarts all telemetry services"
|
||||
printf "%15s %-65s\n" "opt-in" "Opts in to telemetry, and starts telemetry services"
|
||||
printf "%15s %-65s\n" "opt-out" "Opts out of telemetry, and stops telemetry services"
|
||||
printf "%s - Control actions for telemetry services\n" "$SCRIPT"
|
||||
printf "\n"
|
||||
printf "$format" "stop" "Stops all running telemetry services"
|
||||
printf "$format" "start" "Starts all telemetry services"
|
||||
printf "$format" "restart" "Restarts all telemetry services"
|
||||
printf "$format" "is-active" "Checks if telemd is active"
|
||||
printf "$format" "opt-in" "Opts in to telemetry, and starts telemetry services"
|
||||
printf "$format" "opt-out" "Opts out of telemetry, and stops telemetry services"
|
||||
printf "$format" "journal" "Prints telemd journal contents. Use -h argument with"
|
||||
printf "$format" "" "command for more options"
|
||||
printf "\n"
|
||||
exit 2
|
||||
}
|
||||
|
||||
if [ $# -ne 1 ]; then
|
||||
usage
|
||||
if [ "$1" != "journal" ] && [ $# -ne 1 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
if [ $EUID -ne 0 ]; then
|
||||
@@ -105,6 +133,10 @@ case $SUBCOMMAND in
|
||||
telem_start ;;
|
||||
restart)
|
||||
telem_restart ;;
|
||||
is-active)
|
||||
telem_is_active ;;
|
||||
journal)
|
||||
telem_journal_cli "$@" ;;
|
||||
*)
|
||||
notice "Unknown command passed to $SCRIPT"
|
||||
usage ;;
|
||||
|
||||
+5
-1
@@ -33,7 +33,11 @@ static const char *header_names[] = {
|
||||
TM_SYSTEM_BUILD_STR,
|
||||
TM_KERNEL_VERSION_STR,
|
||||
TM_PAYLOAD_VERSION_STR,
|
||||
TM_SYSTEM_NAME_STR
|
||||
TM_SYSTEM_NAME_STR,
|
||||
TM_BOARD_NAME_STR,
|
||||
TM_CPU_MODEL_STR,
|
||||
TM_BIOS_VERSION_STR,
|
||||
TM_EVENT_ID_STR
|
||||
};
|
||||
|
||||
const char *get_header_name(int ind)
|
||||
|
||||
+18
-2
@@ -35,6 +35,10 @@
|
||||
#define TM_KERNEL_VERSION 8
|
||||
#define TM_PAYLOAD_VERSION 9
|
||||
#define TM_SYSTEM_NAME 10
|
||||
#define TM_BOARD_NAME 11
|
||||
#define TM_CPU_MODEL 12
|
||||
#define TM_BIOS_VERSION 13
|
||||
#define TM_EVENT_ID 14
|
||||
|
||||
#define TM_RECORD_VERSION_STR "record_format_version"
|
||||
#define TM_CLASSIFICATION_STR "classification"
|
||||
@@ -47,14 +51,26 @@
|
||||
#define TM_KERNEL_VERSION_STR "kernel_version"
|
||||
#define TM_PAYLOAD_VERSION_STR "payload_format_version"
|
||||
#define TM_SYSTEM_NAME_STR "system_name"
|
||||
#define TM_BOARD_NAME_STR "board_name"
|
||||
#define TM_CPU_MODEL_STR "cpu_model"
|
||||
#define TM_BIOS_VERSION_STR "bios_version"
|
||||
#define TM_EVENT_ID_STR "event_id"
|
||||
|
||||
#define NUM_HEADERS 11
|
||||
#define NUM_HEADERS 15
|
||||
|
||||
#define EVENT_ID_ALPHAB "0123456789abcdef"
|
||||
#define EVENT_ID_LEN 32
|
||||
|
||||
/* Journal */
|
||||
#define JOURNAL_PATH "/var/log/telemetry/journal"
|
||||
#define JOURNAL_TMPDIR "/var/log/telemetry/"
|
||||
#define RECORD_RETENTION_DIR "/var/log/telemetry/records"
|
||||
|
||||
/* For internal library usage. Bump the version whenever we change the record
|
||||
* structure (e.g. adding or removing a header field). Note that the value
|
||||
* should be an unsigned int.
|
||||
*/
|
||||
static const uint32_t RECORD_FORMAT_VERSION = 2;
|
||||
static const uint32_t RECORD_FORMAT_VERSION = 4;
|
||||
|
||||
#define TM_SITE_VERSION_FILE "/etc/os-release"
|
||||
#define TM_DIST_VERSION_FILE "/usr/lib/os-release"
|
||||
|
||||
+31
-6
@@ -47,8 +47,8 @@ const char *config_key_int[] = { NULL, "record_expiry", "spool_max_size",
|
||||
"byte_window_length", "record_burst_limit",
|
||||
"byte_burst_limit", NULL };
|
||||
|
||||
const char *config_key_bool[] = { NULL, "rate_limit_enabled",
|
||||
"daemon_recycling_enabled", NULL };
|
||||
const char *config_key_bool[] = { NULL, "rate_limit_enabled", "daemon_recycling_enabled",
|
||||
"record_retention_enabled", "record_server_delivery_enabled", NULL };
|
||||
|
||||
static struct configuration config = { { 0 }, { 0 }, { 0 }, false, NULL };
|
||||
|
||||
@@ -91,8 +91,7 @@ bool read_config_from_file(char *config_file, struct configuration *config)
|
||||
keyfile = nc_ini_file_parse(config_file);
|
||||
if (!keyfile) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "ERR: Failed to read config file: %s\n",
|
||||
error->message);
|
||||
fprintf(stderr, "ERR: Failed to read config file\n");
|
||||
#endif
|
||||
return false;
|
||||
} else {
|
||||
@@ -133,8 +132,22 @@ bool read_config_from_file(char *config_file, struct configuration *config)
|
||||
config->boolValues[i] = true;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "ERR: missing key with boolean value: %s\n", config_key_bool[i]);
|
||||
return false;
|
||||
/* New configuration keys, CONF_RECORD_RETENTION_ENABLED and CONF_RECORD_SERVER_DELIVERY_ENABLED
|
||||
* default values, otherwise update will require changes in custom configurations */
|
||||
if (i == CONF_RECORD_RETENTION_ENABLED) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "WARN: missing boolean optional key: %s\n", config_key_bool[i]);
|
||||
#endif
|
||||
config->boolValues[i] = RECORD_RETENTION_ENABLED_DEFAULT;
|
||||
} else if (i == CONF_RECORD_SERVER_DELIVERY_ENABLED) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "WARN: missing boolean optional key: %s\n", config_key_bool[i]);
|
||||
#endif
|
||||
config->boolValues[i] = RECORD_SERVER_DELIVERY_ENABLED_DEFAULT;
|
||||
} else {
|
||||
fprintf(stderr, "ERR: missing key with boolean value: %s\n", config_key_bool[i]);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -357,4 +370,16 @@ bool daemon_recycling_enabled_config(void)
|
||||
initialize_config();
|
||||
return config.boolValues[CONF_DAEMON_RECYCLING_ENABLED];
|
||||
}
|
||||
|
||||
bool record_retention_enabled_config(void)
|
||||
{
|
||||
initialize_config();
|
||||
return config.boolValues[CONF_RECORD_RETENTION_ENABLED];
|
||||
}
|
||||
|
||||
bool record_server_delivery_enabled_config(void)
|
||||
{
|
||||
initialize_config();
|
||||
return config.boolValues[CONF_RECORD_SERVER_DELIVERY_ENABLED];
|
||||
}
|
||||
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define TM_MAX_WINDOW_LENGTH (1 /*h*/ * 60 /*m*/)
|
||||
#define RECORD_RETENTION_ENABLED_DEFAULT false
|
||||
#define RECORD_SERVER_DELIVERY_ENABLED_DEFAULT true
|
||||
|
||||
enum config_str_keys {
|
||||
CONF_STR_MIN = 0,
|
||||
@@ -47,6 +49,8 @@ enum config_bool_keys {
|
||||
CONF_BOOL_MIN = 0,
|
||||
CONF_RATE_LIMIT_ENABLED,
|
||||
CONF_DAEMON_RECYCLING_ENABLED,
|
||||
CONF_RECORD_RETENTION_ENABLED,
|
||||
CONF_RECORD_SERVER_DELIVERY_ENABLED,
|
||||
CONF_BOOL_MAX
|
||||
};
|
||||
|
||||
@@ -117,4 +121,10 @@ const char *get_tidheader_config(void);
|
||||
/* Gets whether recycling is enabled */
|
||||
bool daemon_recycling_enabled_config(void);
|
||||
|
||||
/* Gets whether local retention of records is enabled */
|
||||
bool record_retention_enabled_config(void);
|
||||
|
||||
/* Gets whether records should be sent to server_addr */
|
||||
bool record_server_delivery_enabled_config(void);
|
||||
|
||||
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
[Unit]
|
||||
Description=Telemetrics BERT Probe
|
||||
Requires=telemd.socket
|
||||
After=telemd.socket
|
||||
ConditionPathExists=!/etc/telemetrics/opt-out
|
||||
ConditionPathExists=/sys/firmware/acpi/tables/data/BERT
|
||||
|
||||
[Service]
|
||||
ExecStart=@bindir@/bertprobe
|
||||
User=telemetry
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,46 @@
|
||||
[settings]
|
||||
server=http://127.0.0.1
|
||||
|
||||
cainfo=/tmp/cacert.crt
|
||||
|
||||
tidheader=X-Telemetry-TID:\s6907c830-eed9-4ce9-81ae-76daf8d88f0f
|
||||
|
||||
socket_path=/tmp/test_telem_socket
|
||||
|
||||
#record expiry time in minutes
|
||||
record_expiry=1200
|
||||
|
||||
spool_dir=/tmp/spool
|
||||
|
||||
#maximum size of the spool directory in KB
|
||||
spool_max_size=1024
|
||||
|
||||
#time in seconds for processing spool
|
||||
spool_process_time=900
|
||||
|
||||
#rate limiting record burst limit
|
||||
record_burst_limit=100
|
||||
|
||||
#rate limiting record window length
|
||||
record_window_length = 15
|
||||
|
||||
#rate limiting byte burst limit
|
||||
byte_burst_limit = 1000
|
||||
|
||||
#rate limiting byte window length
|
||||
byte_window_length=20
|
||||
|
||||
#rate limit enabled
|
||||
rate_limit_enabled=true
|
||||
|
||||
#rate limit strategy if record not send
|
||||
rate_limit_strategy=spool
|
||||
|
||||
#daemon recycling enabled
|
||||
daemon_recycling_enabled=true
|
||||
|
||||
#server delivery disable
|
||||
record_server_delivery_enabled=false
|
||||
|
||||
#local copy enabled
|
||||
record_retention_enabled=true
|
||||
+15
-1
@@ -4,14 +4,17 @@ pathfix = @sed \
|
||||
-e 's|@libdir[@]|$(libdir)|g' \
|
||||
-e 's|@localstatedir[@]|$(localstatedir)|g' \
|
||||
-e 's|@PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' \
|
||||
-e 's|@SOCKETDIR[@]|$(SOCKETDIR)|g'
|
||||
-e 's|@SOCKETDIR[@]|$(SOCKETDIR)|g' \
|
||||
-e 's|@systemctldir[@]|$(SYSTEMD_SYSTEMCTLDIR)|g'
|
||||
|
||||
EXTRA_DIST += \
|
||||
%D%/40-core-ulimit.conf \
|
||||
%D%/40-crash-probe.conf.in \
|
||||
%D%/example.conf \
|
||||
%D%/example.1.conf \
|
||||
%D%/hprobe.service.in \
|
||||
%D%/hprobe.timer \
|
||||
%D%/bert-probe.service.in \
|
||||
%D%/journal-probe.service.in \
|
||||
%D%/oops-probe.service.in \
|
||||
%D%/pstore-probe.service.in \
|
||||
@@ -21,6 +24,7 @@ EXTRA_DIST += \
|
||||
%D%/telemd.path.in \
|
||||
%D%/telemd.service.in \
|
||||
%D%/telemd.socket.in \
|
||||
%D%/telemd-update-trigger.service.in \
|
||||
%D%/telemetrics-dirs.conf.in \
|
||||
%D%/telemetrics.conf.in
|
||||
|
||||
@@ -46,6 +50,7 @@ systemdunitdir = @SYSTEMD_UNITDIR@
|
||||
systemdunit_DATA = \
|
||||
%D%/hprobe.service \
|
||||
%D%/hprobe.timer \
|
||||
%D%/bert-probe.service \
|
||||
%D%/journal-probe.service \
|
||||
%D%/oops-probe.service \
|
||||
%D%/pstore-probe.service \
|
||||
@@ -53,11 +58,15 @@ systemdunit_DATA = \
|
||||
%D%/pstore-clean.service \
|
||||
%D%/telemd.service \
|
||||
%D%/telemd.socket \
|
||||
%D%/telemd-update-trigger.service \
|
||||
%D%/telemd.path
|
||||
|
||||
%D%/hprobe.service: %D%/hprobe.service.in
|
||||
$(pathfix) < $< > $@
|
||||
|
||||
%D%/bert-probe.service: %D%/bert-probe.service.in
|
||||
$(pathfix) < $< > $@
|
||||
|
||||
%D%/journal-probe.service: %D%/journal-probe.service.in
|
||||
$(pathfix) < $< > $@
|
||||
|
||||
@@ -82,6 +91,9 @@ systemdunit_DATA = \
|
||||
%D%/telemd.path: %D%/telemd.path.in
|
||||
$(pathfix) < $< > $@
|
||||
|
||||
%D%/telemd-update-trigger.service: %D%/telemd-update-trigger.service.in
|
||||
$(pathfix) < $< > $@
|
||||
|
||||
sysctldir = @SYSTEMD_SYSCTLDIR@
|
||||
sysctl_DATA = %D%/40-crash-probe.conf
|
||||
|
||||
@@ -95,6 +107,7 @@ clean-local:
|
||||
-rm -f %D%/telemd.service \
|
||||
%D%/telemd.socket \
|
||||
%D%/telemd.path \
|
||||
%D%/telemd-update-trigger.service \
|
||||
%D%/telemetrics.conf \
|
||||
%D%/telemetrics-dirs.conf \
|
||||
%D%/libtelemetry.pc \
|
||||
@@ -105,4 +118,5 @@ clean-local:
|
||||
%D%/klogscanner.service \
|
||||
%D%/pstore-clean.service \
|
||||
%D%/hprobe.service \
|
||||
%D%/bert-probe.service \
|
||||
%D%/.dirstamp
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
[Unit]
|
||||
Description=Restart Telemetrics Daemon On Update
|
||||
BindsTo=update-triggers.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=@systemctldir@/systemctl try-restart telemd.service
|
||||
@@ -1,5 +1,7 @@
|
||||
d @localstatedir@/lib/telemetry 0755 telemetry telemetry -
|
||||
d @localstatedir@/spool/telemetry 0750 telemetry telemetry -
|
||||
d @localstatedir@/log/telemetry 0750 telemetry telemetry -
|
||||
d @localstatedir@/log/telemetry/records 0750 telemetry telemetry -
|
||||
d @localstatedir@/cache/telemetry 0750 telemetry telemetry -
|
||||
d @localstatedir@/cache/telemetry/oops 0750 telemetry telemetry -
|
||||
d @localstatedir@/cache/telemetry/pstore 0750 telemetry telemetry -
|
||||
|
||||
@@ -55,3 +55,13 @@ rate_limit_strategy=spool
|
||||
# has not any client nor spool data, then it exits.
|
||||
# this is to ensure that latest code runs.
|
||||
daemon_recycling_enabled=true
|
||||
|
||||
# record server delivery enabled - when enabled records will be delivered
|
||||
# to server otherwise records will be ignored. This configuration can be used
|
||||
# with 'record_retention_enable' configuration value to keep records local only.
|
||||
record_server_delivery_enabled=true
|
||||
|
||||
# record retention enabled - when enabled a copy of reported telemetry records
|
||||
# will be kept locally. This configuration combined with 'record_server_delivery_enabled'
|
||||
# value can be used to keep records local only.
|
||||
record_retention_enabled=false
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* This program is part of the Clear Linux Project
|
||||
*
|
||||
* Copyright 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms and conditions 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 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "journal.h"
|
||||
|
||||
void print_usage(void)
|
||||
{
|
||||
printf(" Usage\n");
|
||||
printf(" -r, --record_id Print record with specific record_id\n");
|
||||
printf(" -e, --event_id Print records with specific event_id\n");
|
||||
printf(" -c, --classification Print records with specific classification\n");
|
||||
printf(" -b, --boot_id Print records with specific boot_id\n");
|
||||
printf(" -i, --include_record Include record content\n");
|
||||
printf(" -V, --verbose Verbose output\n");
|
||||
printf(" -h, --help Display this help message\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
|
||||
int rc = EXIT_SUCCESS;
|
||||
int count = 0;
|
||||
int verbose_output = 0;
|
||||
int record = 0;
|
||||
char *boot_id = NULL;
|
||||
char *record_id = NULL;
|
||||
char *event_id = NULL;
|
||||
char *classification = NULL;
|
||||
struct TelemJournal *telem_journal = NULL;
|
||||
|
||||
/** opts */
|
||||
int c;
|
||||
int opt_index = 0;
|
||||
struct option opts[] = {
|
||||
{ "record_id", 1, NULL, 'r' },
|
||||
{ "event_id", 1, NULL, 'e' },
|
||||
{ "classification", 1, NULL, 'c' },
|
||||
{ "boot_id", 1, NULL, 'b' },
|
||||
{ "verbose", 0, NULL, 'V' },
|
||||
{ "include_record", 0, NULL, 'i' },
|
||||
{ "help", 0, NULL, 'h' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
while ((c = getopt_long(argc, argv, "r:e:c:b:Vih", opts, &opt_index)) != -1) {
|
||||
switch (c) {
|
||||
case 'r':
|
||||
record_id = optarg;
|
||||
break;
|
||||
case 'e':
|
||||
event_id = optarg;
|
||||
break;
|
||||
case 'c':
|
||||
classification = optarg;
|
||||
break;
|
||||
case 'b':
|
||||
boot_id = optarg;
|
||||
break;
|
||||
case 'V':
|
||||
verbose_output = 1;
|
||||
break;
|
||||
case 'i':
|
||||
record = 1;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
case '?':
|
||||
/** default */
|
||||
print_usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if ((telem_journal = open_journal(JOURNAL_PATH))) {
|
||||
if (verbose_output) {
|
||||
fprintf(stdout, "%-30s %-27s %-32s %-32s %-36s\n", "Classification", "Time stamp",
|
||||
"Record ID", "Event ID", "Boot ID");
|
||||
}
|
||||
count = print_journal(telem_journal, classification, record_id, event_id, boot_id, record);
|
||||
if (verbose_output) {
|
||||
fprintf(stdout, "Total records: %d\n", count);
|
||||
}
|
||||
close_journal(telem_journal);
|
||||
} else {
|
||||
fprintf(stderr, "Unable to open journal\n");
|
||||
rc = EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@@ -0,0 +1,707 @@
|
||||
/*
|
||||
* This program is part of the Clear Linux Project
|
||||
*
|
||||
* Copyright 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms and conditions 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 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#define ID_LEN 32
|
||||
#define BOOTID_LEN 37 // Includes the \n character at the end
|
||||
#define BOOTID_FILE "/proc/sys/kernel/random/boot_id"
|
||||
#define MID_BUFF 1024
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/uio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "util.h"
|
||||
#include "common.h"
|
||||
#include "journal.h"
|
||||
|
||||
/*
|
||||
* Packs journal entry values into one line string separated
|
||||
* by '\036' RS.
|
||||
*
|
||||
* @param entry A pointer to a JournalEntry struct with values
|
||||
* to serialize.
|
||||
* @param buff A pointer to be initialized and set with the
|
||||
* serialized values.
|
||||
*
|
||||
* @return 0 on success, -1 on failure.
|
||||
*/
|
||||
static int serialize_journal_entry(struct JournalEntry *entry, char **buff)
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
if (entry == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (asprintf(buff, "%s\036%lld\036%s\036%s\036%s", entry->record_id, (long long int)entry->timestamp,
|
||||
entry->classification, entry->event_id, entry->boot_id) < 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Error: unable to serialize data in buff\n");
|
||||
#endif
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Frees journal entry struct members and journal entry pointer.
|
||||
*
|
||||
* @param the pointer to the entry structure to free.
|
||||
*/
|
||||
static void free_journal_entry(struct JournalEntry *entry)
|
||||
{
|
||||
if (entry) {
|
||||
free(entry->classification);
|
||||
free(entry->record_id);
|
||||
free(entry->event_id);
|
||||
free(entry->boot_id);
|
||||
free(entry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unpacks a record that was stored in file and initializes a
|
||||
* JournalEntry struct with parsed values.
|
||||
*
|
||||
* @param line A pointer to the data to unpack.
|
||||
* @param entry A pointer to be initialized and set with values
|
||||
* parsed from parameter line.
|
||||
*
|
||||
* @return 0 on success, -1 on failure.
|
||||
*/
|
||||
static int deserialize_journal_entry(char *line, struct JournalEntry **entry)
|
||||
{
|
||||
int rc = -1;
|
||||
size_t len = 0;
|
||||
size_t llen = 0;
|
||||
size_t offset = 0;
|
||||
struct JournalEntry *e = NULL;
|
||||
|
||||
if (line == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
e = malloc(sizeof(struct JournalEntry));
|
||||
if (!e) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
llen = strlen(line);
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
char *out = NULL;
|
||||
if (offset > llen) {
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
len = strcspn(line + offset, "\036\n");
|
||||
out = strndup((line + offset), len);
|
||||
offset += len + 1;
|
||||
if (out) {
|
||||
switch (i) {
|
||||
case 0:
|
||||
e->record_id = out;
|
||||
break;
|
||||
case 1:
|
||||
e->timestamp = atoll(out);
|
||||
free(out);
|
||||
break;
|
||||
case 2:
|
||||
e->classification = out;
|
||||
break;
|
||||
case 3:
|
||||
e->event_id = out;
|
||||
break;
|
||||
case 4:
|
||||
e->boot_id = out;
|
||||
rc = 0;
|
||||
break;
|
||||
default:
|
||||
assert(i < 0 && i > 4);
|
||||
free(out);
|
||||
rc = 1;
|
||||
}
|
||||
} else {
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == 0) {
|
||||
*entry = e;
|
||||
} else {
|
||||
free_journal_entry(e);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of records in journal.
|
||||
*
|
||||
* @param telem_journal Pointer to a telemetry journal
|
||||
* to get record count.
|
||||
*
|
||||
* @return record count
|
||||
*
|
||||
*/
|
||||
static int get_record_count(struct TelemJournal *telem_journal)
|
||||
{
|
||||
int count = 0;
|
||||
size_t len;
|
||||
ssize_t read;
|
||||
char *line = NULL;
|
||||
|
||||
rewind(telem_journal->fptr);
|
||||
// read until the end line by line
|
||||
while ((read = getline(&line, &len, telem_journal->fptr)) != -1) {
|
||||
count++;
|
||||
}
|
||||
free(line);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Serializes JournalEntry and saves it to file.
|
||||
*
|
||||
* @param fptr A FILE pointer.
|
||||
* @param entry A pointer to data.
|
||||
*
|
||||
* @return 0 on succes, !=0 on failure
|
||||
*/
|
||||
static int save_entry(FILE *fptr, struct JournalEntry *entry)
|
||||
{
|
||||
int rc = -1;
|
||||
char *serialized_data = NULL;
|
||||
|
||||
if (fptr == NULL || entry == NULL) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if ((rc = serialize_journal_entry(entry, &serialized_data)) == 0) {
|
||||
#ifdef DEBUG
|
||||
printf("Saving: %s\n", serialized_data);
|
||||
#endif
|
||||
fprintf(fptr, "%s\n", serialized_data);
|
||||
fflush(fptr);
|
||||
free(serialized_data);
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the boot unique identifier from BOOTID_FILE
|
||||
*
|
||||
* @param buff pointer to a BOOTID_LEN allocated
|
||||
*
|
||||
* @return 0 on success, -1 on failure
|
||||
*/
|
||||
static int read_boot_id(char buff[])
|
||||
{
|
||||
int rc = -1;
|
||||
FILE *fs = NULL;
|
||||
|
||||
fs = fopen(BOOTID_FILE, "r");
|
||||
if (!fs) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Unable to open %s for reading: %d\n", BOOTID_FILE, errno);
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (fgets(buff, BOOTID_LEN, fs)) {
|
||||
rc = 0;
|
||||
}
|
||||
fclose(fs);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves the file position indicator n lines.
|
||||
*
|
||||
* @param n Number of lines to skip.
|
||||
* @param fptr A file pointer.
|
||||
* @param found_record A pointer to a function to be called
|
||||
* every time a valid record is found, if
|
||||
* pointer is not set to null.
|
||||
*
|
||||
* @returns 0 on success, on failure -1 if n > existing
|
||||
* lines in file or errno if failure happens
|
||||
* during file operation.
|
||||
*/
|
||||
static int skip_n_lines(int n, FILE *fptr, int (*found_record)(char *))
|
||||
{
|
||||
int rc = 0;
|
||||
size_t len = 0;
|
||||
char *line = NULL;
|
||||
struct JournalEntry *entry = NULL;
|
||||
|
||||
if (fptr == NULL) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "fptr argument to skip_n_lines is invalid\n");
|
||||
#endif
|
||||
// File descriptor in bad state
|
||||
return EBADFD;
|
||||
}
|
||||
|
||||
if (fseek(fptr, 0, 0) != 0) {
|
||||
return errno;
|
||||
}
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (getline(&line, &len, fptr) == -1) {
|
||||
rc = -1;
|
||||
break;
|
||||
}
|
||||
if (found_record != NULL) {
|
||||
deserialize_journal_entry(line, &entry);
|
||||
if (entry) {
|
||||
found_record(entry->record_id);
|
||||
free_journal_entry(entry);
|
||||
entry = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies contents of fptr to a known location.
|
||||
*
|
||||
* @param fptr A file pointer from source file.
|
||||
*
|
||||
* @returns 0 on success, errno on failure
|
||||
*/
|
||||
static int copy_to_tmp(FILE *fptr, char *tmp_path)
|
||||
{
|
||||
int rc = 0;
|
||||
size_t len;
|
||||
char *line = NULL;
|
||||
FILE *fptr_tmp = NULL;
|
||||
|
||||
if (fptr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
fptr_tmp = fopen(tmp_path, "w");
|
||||
if (!fptr_tmp) {
|
||||
return errno;
|
||||
}
|
||||
|
||||
// Copy lines to new file
|
||||
while (getline(&line, &len, fptr) > -1) {
|
||||
if (fprintf(fptr_tmp, "%s", line) < 0) {
|
||||
rc = errno;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (fclose(fptr_tmp) != 0) {
|
||||
rc = errno;
|
||||
#ifdef DEBUG
|
||||
perror("Error: ");
|
||||
#endif
|
||||
}
|
||||
free(line);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Exported function */
|
||||
TelemJournal *open_journal(const char *journal_file)
|
||||
{
|
||||
FILE *fptr = NULL;
|
||||
char boot_id[BOOTID_LEN] = { '\0' };
|
||||
struct TelemJournal *telem_journal;
|
||||
|
||||
// Use default location if journal_file parameter is NULL
|
||||
fptr = (journal_file == NULL) ? fopen(JOURNAL_PATH, "a+") :
|
||||
fopen(journal_file, "a+");
|
||||
|
||||
if (fptr == NULL) {
|
||||
#ifdef DEBUG
|
||||
perror("Error while opening journal file: ");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (read_boot_id(boot_id) != 0) {
|
||||
#ifdef DEBUG
|
||||
perror("Error while reading boot_id: ");
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
telem_journal = malloc(sizeof(struct TelemJournal));
|
||||
if (!telem_journal) {
|
||||
fprintf(stderr, "Unable to allocate more memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
telem_journal->fptr = fptr;
|
||||
telem_journal->journal_file = \
|
||||
(journal_file == NULL) ? strdup(JOURNAL_PATH) : strdup(journal_file);
|
||||
/* boot_id includes \n at the end, strip RC during duplication */
|
||||
telem_journal->boot_id = strndup(boot_id, BOOTID_LEN - 1);
|
||||
telem_journal->record_count = get_record_count(telem_journal);
|
||||
telem_journal->record_count_limit = RECORD_LIMIT;
|
||||
telem_journal->latest_record_id = NULL;
|
||||
telem_journal->prune_entry_callback = NULL;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("Records in db: %d\n", telem_journal->record_count);
|
||||
#endif
|
||||
|
||||
return telem_journal;
|
||||
}
|
||||
|
||||
/* Exported function */
|
||||
void close_journal(TelemJournal *telem_journal)
|
||||
{
|
||||
if (telem_journal) {
|
||||
free(telem_journal->boot_id);
|
||||
free(telem_journal->journal_file);
|
||||
free(telem_journal->latest_record_id);
|
||||
fclose(telem_journal->fptr);
|
||||
free(telem_journal);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if class is a prefix i.e. t/\* or t/t/\*
|
||||
*
|
||||
* @param class A pointer to string with classification
|
||||
* value to check.
|
||||
* @return 1 if class is a prefix, 0 otherwise
|
||||
*/
|
||||
static int is_class_prefix(char *class)
|
||||
{
|
||||
size_t class_len = strlen(class);
|
||||
return (strcmp((char *)(class + class_len - 2), "/*") == 0) ? 1 : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Print records content
|
||||
*
|
||||
* @param record_id Unique record identifier
|
||||
*
|
||||
*/
|
||||
static void print_record(char *record_id)
|
||||
{
|
||||
int rc = 0;
|
||||
size_t read = 0;
|
||||
char buff[MID_BUFF] = { '\0' };
|
||||
char *filepath = NULL;
|
||||
FILE *recordfp = NULL;
|
||||
|
||||
rc = asprintf(&filepath, "%s/%s", RECORD_RETENTION_DIR, record_id);
|
||||
if (rc == -1) {
|
||||
// just bail out, there are worse problems
|
||||
return;
|
||||
}
|
||||
|
||||
recordfp = fopen(filepath, "r");
|
||||
if (!recordfp) {
|
||||
telem_perror("Error when opening a record to print");
|
||||
return;
|
||||
}
|
||||
|
||||
while ((read = fread(buff, 1, sizeof(buff), recordfp)) > 0) {
|
||||
fwrite(buff, 1, read, stdout);
|
||||
}
|
||||
|
||||
free(filepath);
|
||||
fclose(recordfp);
|
||||
}
|
||||
|
||||
/* Exported function */
|
||||
int print_journal(TelemJournal *telem_journal, char *classification,
|
||||
char *record_id, char *event_id, char *boot_id,
|
||||
bool include_record)
|
||||
{
|
||||
int n = 0;
|
||||
int rc = 0;
|
||||
int count = 0;
|
||||
char str_time[80] = { '\0' };
|
||||
char *line = NULL;
|
||||
size_t len = 0;
|
||||
FILE *journal_fileptr = NULL;
|
||||
struct tm ts;
|
||||
struct JournalEntry *entry = NULL;
|
||||
|
||||
if (telem_journal == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
journal_fileptr = fopen(telem_journal->journal_file, "r");
|
||||
if (!journal_fileptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Advance file pointer to line n
|
||||
n = telem_journal->record_count - telem_journal->record_count_limit;
|
||||
if (n > 0) {
|
||||
rc = skip_n_lines(n, journal_fileptr, NULL);
|
||||
if (rc == -1) {
|
||||
return rc;
|
||||
} else if (rc != 0) {
|
||||
fprintf(stderr, "An error occurred while advancing journal file: %s\n", strerror(rc));
|
||||
}
|
||||
}
|
||||
|
||||
while (getline(&line, &len, journal_fileptr) != -1) {
|
||||
deserialize_journal_entry(line, &entry);
|
||||
if (entry) {
|
||||
/* filter entry out if one is provided */
|
||||
if (record_id != NULL && strcmp(entry->record_id, record_id) != 0) {
|
||||
goto skip_print;
|
||||
}
|
||||
if (boot_id != NULL && strcmp(entry->boot_id, boot_id) != 0) {
|
||||
goto skip_print;
|
||||
}
|
||||
if (event_id != NULL && strcmp(entry->event_id, event_id) != 0) {
|
||||
goto skip_print;
|
||||
}
|
||||
// In the case of class checking prefixes is an option
|
||||
if (classification != NULL) {
|
||||
// Check prefixes when classification ends in /*, otherwise use strcomp
|
||||
if (is_class_prefix(classification)) {
|
||||
if (strncmp(entry->classification, classification, strlen(classification) - 1) != 0) {
|
||||
continue;
|
||||
}
|
||||
} else if (strcmp(entry->classification, classification) != 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* end filters section */
|
||||
ts = *localtime(&entry->timestamp);
|
||||
if (strftime(str_time, sizeof(str_time), "%a %Y-%m-%d %H:%M:%S %Z", &ts) == 0) {
|
||||
continue;
|
||||
}
|
||||
/* print record metadata */
|
||||
fprintf(stdout, "%-30s %s %s %s %s\n", entry->classification, str_time, entry->record_id, entry->event_id, entry->boot_id);
|
||||
/* print record content */
|
||||
if (include_record) {
|
||||
print_record(entry->record_id);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
skip_print:
|
||||
free_journal_entry(entry);
|
||||
}
|
||||
free(line);
|
||||
fclose(journal_fileptr);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validation for event id. Thic check makes sure
|
||||
* that an event_id is a 32 hexadecimal chars long.
|
||||
*
|
||||
* @param event_id A pointer to id value.
|
||||
*
|
||||
* @return 0 on success, 1 on failure
|
||||
*/
|
||||
static int validate_event_id(char *event_id)
|
||||
{
|
||||
const char alphab[] = EVENT_ID_ALPHAB;
|
||||
|
||||
if (event_id == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strlen(event_id) != EVENT_ID_LEN) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (strspn(event_id, alphab) != EVENT_ID_LEN) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Exported function */
|
||||
int new_journal_entry(TelemJournal *telem_journal, char *classification,
|
||||
time_t timestamp, char *event_id)
|
||||
{
|
||||
int rc = 1;
|
||||
char boot_id[BOOTID_LEN] = { '\0' };
|
||||
char *record_id = NULL;
|
||||
struct JournalEntry *entry = NULL;
|
||||
|
||||
if (telem_journal == NULL) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Error: telem_journal was not initialized\n");
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (validate_classification(classification) != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (validate_event_id(event_id) != 0) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
entry = malloc(sizeof(struct JournalEntry));
|
||||
if (!entry) {
|
||||
fprintf(stderr, "Error: unable to allocate more memory\n");
|
||||
return rc;
|
||||
}
|
||||
entry->classification = NULL;
|
||||
entry->record_id = NULL;
|
||||
entry->event_id = NULL;
|
||||
entry->boot_id = NULL;
|
||||
|
||||
if (get_random_id(&record_id) != 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Error: unable to generate random id\n");
|
||||
#endif
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (read_boot_id(boot_id) != 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Error: unable to read boot_id\n");
|
||||
#endif
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if ((entry->classification = strdup(classification)) == NULL) {
|
||||
goto quit;
|
||||
}
|
||||
if ((entry->event_id = strdup(event_id)) == NULL) {
|
||||
goto quit;
|
||||
}
|
||||
|
||||
entry->record_id = record_id;
|
||||
/* boot_id includes \n at the end, strip RC during duplication */
|
||||
entry->boot_id = strndup(boot_id, BOOTID_LEN - 1);
|
||||
entry->timestamp = timestamp;
|
||||
|
||||
if ((rc = save_entry(telem_journal->fptr, entry)) == 0) {
|
||||
telem_journal->record_count = telem_journal->record_count + 1;
|
||||
#ifdef DEBUG
|
||||
fprintf(stdout, "%d records in journal\n", telem_journal->record_count);
|
||||
#endif
|
||||
}
|
||||
|
||||
free(telem_journal->latest_record_id);
|
||||
telem_journal->latest_record_id = strdup(entry->record_id);
|
||||
|
||||
quit:
|
||||
free_journal_entry(entry);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Exported function */
|
||||
int prune_journal(struct TelemJournal *telem_journal, char *tmp_dir)
|
||||
{
|
||||
|
||||
int rc = 1;
|
||||
int count = 0;
|
||||
int deviation = DEVIATION;
|
||||
char *tmp_file_path = NULL;
|
||||
|
||||
if (telem_journal == NULL) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
if (telem_journal->record_count > (deviation + telem_journal->record_count_limit)) {
|
||||
count = telem_journal->record_count - telem_journal->record_count_limit;
|
||||
|
||||
// jump to line# count
|
||||
if ((rc = skip_n_lines(count, telem_journal->fptr, telem_journal->prune_entry_callback)) != 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Error: skipping %d journal lines\n", count);
|
||||
#endif
|
||||
// if rc == -1 (n > #lines in file, change to errno style)
|
||||
return (rc == -1) ? EADDRNOTAVAIL : rc;
|
||||
}
|
||||
// Use default if not tmp_dir is specified
|
||||
if (tmp_dir == NULL) {
|
||||
if ((asprintf(&tmp_file_path, "%s/.journal", JOURNAL_TMPDIR) == -1)) {
|
||||
return ENOMEM;
|
||||
}
|
||||
} else {
|
||||
if ((asprintf(&tmp_file_path, "%s/.journal", tmp_dir) == -1)) {
|
||||
return ENOMEM;
|
||||
}
|
||||
}
|
||||
// create new file with rest of file
|
||||
if ((rc = copy_to_tmp(telem_journal->fptr, tmp_file_path)) != 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Error: copying partial journal to temp journal file\n");
|
||||
#endif
|
||||
goto quit;
|
||||
}
|
||||
// close file handler
|
||||
if ((rc = fclose(telem_journal->fptr)) != 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Error: closing journal file handler\n");
|
||||
#endif
|
||||
goto quit;
|
||||
}
|
||||
// overwrite file
|
||||
if ((rc = rename(tmp_file_path, telem_journal->journal_file)) != 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Error: while overwriting journal file\n");
|
||||
#endif
|
||||
goto quit;
|
||||
}
|
||||
// reopen file handler
|
||||
telem_journal->fptr = fopen(telem_journal->journal_file, "a+");
|
||||
if (!telem_journal->fptr) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Error: re-opening journal file\n");
|
||||
#endif
|
||||
return rc;
|
||||
}
|
||||
// update record count
|
||||
telem_journal->record_count = telem_journal->record_count - count;
|
||||
#ifdef DEBUG
|
||||
fprintf(stdout, "record_count: %d\n", telem_journal->record_count);
|
||||
#endif
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
quit:
|
||||
free(tmp_file_path);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* This program is part of the Clear Linux Project
|
||||
*
|
||||
* Copyright 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms and conditions 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 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
/* default record limit */
|
||||
#define RECORD_LIMIT 100
|
||||
#define DEVIATION 50
|
||||
|
||||
#include <time.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
/* Journal entry type */
|
||||
typedef struct JournalEntry {
|
||||
time_t timestamp;
|
||||
char *classification;
|
||||
char *record_id;
|
||||
char *event_id;
|
||||
char *boot_id;
|
||||
} JournalEntry;
|
||||
|
||||
/* Telemetry journal type */
|
||||
typedef struct TelemJournal {
|
||||
FILE *fptr;
|
||||
char *journal_file;
|
||||
char *boot_id;
|
||||
char *latest_record_id;
|
||||
int record_count;
|
||||
int record_count_limit;
|
||||
int (*prune_entry_callback)(char *);
|
||||
} TelemJournal;
|
||||
|
||||
/**
|
||||
* Telemetry journal initialization.
|
||||
*
|
||||
* @param journal_file A pointer to a string containing
|
||||
* the full path to file used as journal storage.
|
||||
* If journal_file is set to NULL a default value
|
||||
* will be used.
|
||||
*
|
||||
* @returns a telemetry journal structure in success or
|
||||
* NULL in case of failure.
|
||||
*/
|
||||
TelemJournal *open_journal(const char *journal_file);
|
||||
|
||||
/**
|
||||
* Closes journal file and deallocates memory that was
|
||||
* previously initialized by open_journal call.
|
||||
*
|
||||
* @param telem_journal A pointer to struct that has a
|
||||
* reference to journal file pointer and other
|
||||
* members.
|
||||
*/
|
||||
void close_journal(TelemJournal *telem_journal);
|
||||
|
||||
/**
|
||||
* Prints journal contents to stdout. Use function parameters
|
||||
* to filter journal entries to print.
|
||||
*
|
||||
* @param telem_journal A pointer to struct initialized
|
||||
* by open_journal call.
|
||||
* @param classification A pointer to string used as
|
||||
* classification filter.
|
||||
* @param record_id A pointer to string used as record_id filter.
|
||||
* @param event_id A pointer to string used as event_id filter.
|
||||
* @param boot_id A pointer to string used as boor_id filter.
|
||||
* @param include_record A flag to control record content print.
|
||||
*
|
||||
* @return the number of lines printed to stdout on success, -1
|
||||
* on failure.
|
||||
*/
|
||||
int print_journal(TelemJournal *telem_journal, char *classification,
|
||||
char *record_id, char *event_id, char *boot_id,
|
||||
bool include_record);
|
||||
|
||||
/**
|
||||
* Creates a new entry in journal.
|
||||
*
|
||||
* @param telem_journal A pointer to telemetry journal.
|
||||
* @param classification A pointer to a classification value.
|
||||
* @param timestamp Record creation time stamp value.
|
||||
* @param event_id A pointer to a unique id value for record
|
||||
* event.
|
||||
*
|
||||
* @return 0 on success 1 on failure.
|
||||
*/
|
||||
int new_journal_entry(TelemJournal *telem_journal, char *classification,
|
||||
time_t timestamp, char *event_id);
|
||||
|
||||
/**
|
||||
* Checks number of lines in log and prunes the oldest records
|
||||
* if journal grows more than telem_journal->record_count_limit.
|
||||
*
|
||||
* @param telem_journal A pointer to telemetry journal struct
|
||||
* returned by open_journal call.
|
||||
* @param tmp_dir A pointer to a string with the path to use for
|
||||
* temp file during pruning process.
|
||||
*
|
||||
* @return 0 on success, errno on failure
|
||||
*/
|
||||
int prune_journal(TelemJournal *telem_journal, char *tmp_dir);
|
||||
|
||||
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
|
||||
@@ -0,0 +1,9 @@
|
||||
bin_PROGRAMS += \
|
||||
%D%/telem_journal
|
||||
|
||||
%C%_telem_journal_SOURCES = %D%/cli.c \
|
||||
%D%/journal.c \
|
||||
src/util.c \
|
||||
src/common.c
|
||||
|
||||
# vim: filetype=automake tabstop=8 shiftwidth=8 noexpandtab
|
||||
+8
-3
@@ -5,7 +5,11 @@ bin_PROGRAMS = %D%/telemd
|
||||
%D%/telemdaemon.c \
|
||||
%D%/telemdaemon.h \
|
||||
%D%/spool.c \
|
||||
%D%/spool.h
|
||||
%D%/spool.h \
|
||||
%D%/journal/journal.c \
|
||||
%D%/journal/journal.h \
|
||||
%D%/retention.c \
|
||||
%D%/retention.h
|
||||
|
||||
%C%_telemd_LDADD = $(CURL_LIBS) \
|
||||
%D%/libtelem-shared.la
|
||||
@@ -34,9 +38,9 @@ endif
|
||||
endif
|
||||
|
||||
# set library version info
|
||||
SHAREDLIB_CURRENT=3
|
||||
SHAREDLIB_CURRENT=4
|
||||
SHAREDLIB_REVISION=0
|
||||
SHAREDLIB_AGE=0
|
||||
SHAREDLIB_AGE=1
|
||||
|
||||
noinst_LTLIBRARIES = %D%/libtelem-shared.la
|
||||
|
||||
@@ -46,6 +50,7 @@ noinst_LTLIBRARIES = %D%/libtelem-shared.la
|
||||
%D%/configuration.c \
|
||||
%D%/nica/inifile.c \
|
||||
%D%/nica/hashmap.c \
|
||||
%D%/nica/b64enc.c \
|
||||
%D%/configuration.h \
|
||||
%D%/common.c \
|
||||
%D%/common.h
|
||||
|
||||
+18
@@ -49,6 +49,7 @@
|
||||
#include "log.h"
|
||||
#include "telemdaemon.h"
|
||||
#include "configuration.h"
|
||||
#include "retention.h"
|
||||
#include "spool.h"
|
||||
|
||||
/*
|
||||
@@ -78,6 +79,7 @@ int main(int argc, char **argv)
|
||||
int c;
|
||||
char *config_file = NULL;
|
||||
int opt_index = 0;
|
||||
nfds_t initial_nfds = 0;
|
||||
sigset_t mask;
|
||||
//bool interrupted = false;
|
||||
|
||||
@@ -121,6 +123,11 @@ int main(int argc, char **argv)
|
||||
}
|
||||
initialize_daemon(&daemon);
|
||||
|
||||
/* Register record retention delete action as a callback to prune entry */
|
||||
if (daemon.record_journal) {
|
||||
daemon.record_journal->prune_entry_callback = &delete_record_by_id;
|
||||
}
|
||||
|
||||
sigemptyset(&mask);
|
||||
|
||||
if (sigaddset(&mask, SIGHUP) != 0) {
|
||||
@@ -244,9 +251,18 @@ int main(int argc, char **argv)
|
||||
|
||||
time_t last_refresh_time = time(NULL);
|
||||
|
||||
/* Save initial count for non connection fds */
|
||||
initial_nfds = daemon.nfds;
|
||||
|
||||
/* Loop to accept clients */
|
||||
while (1) {
|
||||
malloc_trim(0);
|
||||
if (initial_nfds == daemon.nfds) {
|
||||
ret = prune_journal(daemon.record_journal, JOURNAL_TMPDIR);
|
||||
if (ret != 0) {
|
||||
telem_log(LOG_WARNING, "Unable to prune journal\n");
|
||||
}
|
||||
}
|
||||
ret = poll(daemon.pollfds, daemon.nfds, spool_process_time * 1000);
|
||||
if (ret == -1) {
|
||||
telem_perror("Failed to poll daemon file descriptors");
|
||||
@@ -362,6 +378,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
clean_exit:
|
||||
close_journal(daemon.record_journal);
|
||||
|
||||
/* Free memory before exiting */
|
||||
while ((cl = LIST_FIRST(&(daemon.client_head))) != NULL) {
|
||||
remove_client(&(daemon.client_head), cl);
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* This file is part of libnica.
|
||||
*
|
||||
* Copyright © 2017 Intel Corporation
|
||||
*
|
||||
* libnica 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include "b64enc.h"
|
||||
|
||||
#define B64_LINE_LEN 76
|
||||
|
||||
static int padding[] = {0, 2, 1, 0};
|
||||
static char table[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
|
||||
/*
|
||||
* base 64 encoding of 3 bytes to 4 printable characters
|
||||
* (https://tools.ietf.org/html/rfc4648).
|
||||
*
|
||||
* i.e. (Reference: https://en.wikipedia.org/wiki/Base64)
|
||||
*
|
||||
* [ M ] [ a ] [ n ]
|
||||
* bin 01001101 01100001 01101110
|
||||
*
|
||||
* b64 01001101 01100001 01101110 >> 18 & 0x3F -> 010011 -> ( 19 dec) T
|
||||
* ------
|
||||
*
|
||||
* b64 01001101 01100001 01101110 >> 12 & 0x3F -> 010110 -> ( 22 dec) W
|
||||
* -------
|
||||
*
|
||||
* b64 01001101 01100001 01101110 >> 6 & 0x3F -> 000101 -> ( 5 dec) F
|
||||
* -------
|
||||
*
|
||||
* b64 01001101 01100001 01101110 >> 0 & 0x3F -> 101110 -> (117 dec) u
|
||||
* ------
|
||||
*
|
||||
*/
|
||||
static void b64_3b(char bin[3], char *out) {
|
||||
|
||||
uint32_t x = (((uint32_t) bin[0] << 16) & 0xFF0000) |
|
||||
(((uint32_t) bin[1] << 8) & 0xFF00) |
|
||||
(((uint32_t) bin[2]) & 0xFF);
|
||||
|
||||
out[3] = table[x & 0x3F];
|
||||
out[2] = table[x >> 6 & 0x3F];
|
||||
out[1] = table[x >> 12 & 0x3F];
|
||||
out[0] = table[x >> 18 & 0x3F];
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Provide padding to already initialized b64 output
|
||||
*/
|
||||
static void b64_padding(char *out, int pad_size) {
|
||||
|
||||
if (pad_size > 0) {
|
||||
*out++ = '=';
|
||||
}
|
||||
|
||||
if (pad_size > 1) {
|
||||
*out++ = '=';
|
||||
}
|
||||
|
||||
*out = '\0';
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Encode file contents as b64 string
|
||||
*/
|
||||
int nc_b64enc_file(FILE *fh, char *buff, size_t buff_size) {
|
||||
|
||||
int ret_val = 1;
|
||||
int out_count = 0;
|
||||
int pad_size = 0;
|
||||
char *buff_ptr = buff;
|
||||
char bin[3] = {0, 0, 0};
|
||||
size_t len = 0;
|
||||
|
||||
while ((len = fread(bin, 1, 3, fh)) > 0) {
|
||||
b64_3b(bin, buff_ptr);
|
||||
/*
|
||||
Reset 2nd and 3rd bytes in case only one byte was read. If these
|
||||
bytes are not clean b64 output will be corrupted with old bits.
|
||||
*/
|
||||
bin[1] = bin[2] = 0;
|
||||
/*
|
||||
Advance pointer to the next free position of the b64 encoded
|
||||
buffer. This happens to be len + 1 (as longs as len >= 1 and len <= 3)
|
||||
|
||||
len = 1 byte -> b64 -> 2 bytes (or len + 1)
|
||||
len = 2 bytes -> b64 -> 3 bytes (or len + 1)
|
||||
len = 3 bytes -> b64 -> 4 bytes (or len + 1)
|
||||
*/
|
||||
buff_ptr += (len + 1);
|
||||
/*
|
||||
Line break every 76 characters
|
||||
*/
|
||||
out_count += (int) (len + 1);
|
||||
if (out_count % B64_LINE_LEN == 0) {
|
||||
*buff_ptr++ = '\n';
|
||||
}
|
||||
pad_size = padding[len];
|
||||
/*
|
||||
Check not to overflow buffer
|
||||
|
||||
buffer size <= b64 characters + padding length + null termination
|
||||
*/
|
||||
if (buff_size <= (size_t) (buff_ptr - buff) + (size_t) pad_size + 1) {
|
||||
ret_val = 0;
|
||||
goto end_b64_enc;
|
||||
}
|
||||
}
|
||||
|
||||
b64_padding(buff_ptr, pad_size);
|
||||
|
||||
end_b64_enc:
|
||||
|
||||
return ret_val;
|
||||
}
|
||||
|
||||
|
||||
int nc_b64enc_filename(const char *filename, char *buff, size_t buff_size) {
|
||||
|
||||
int ret = 0;
|
||||
FILE *fh = NULL;
|
||||
|
||||
fh = fopen(filename, "rb");
|
||||
|
||||
if (fh == NULL) {
|
||||
goto nc_b64_clean;
|
||||
}
|
||||
|
||||
ret = nc_b64enc_file(fh, buff, buff_size);
|
||||
|
||||
nc_b64_clean:
|
||||
|
||||
if (fh) {
|
||||
fclose(fh);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* This file is part of libnica.
|
||||
*
|
||||
* Copyright © 2017 Intel Corporation
|
||||
*
|
||||
* libnica 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 is a chained base64 encode implementation.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "macros.h"
|
||||
|
||||
/*
|
||||
* Encodes contents of file handler in base64
|
||||
*
|
||||
* @param fh File handler to encode as base64
|
||||
* @param buff Output buffer where the base64 output should be written
|
||||
* @param buff_size Size of the output buffer
|
||||
*
|
||||
* @returns 1 in success and 0 in failure
|
||||
*/
|
||||
_nica_public_ int nc_b64enc_file(FILE *fh, char *buff, size_t buff_size);
|
||||
|
||||
|
||||
/*
|
||||
* Encodes contents of file (filename) in base64
|
||||
*
|
||||
* @param filename File to encode as base64
|
||||
* @param buff Output buffer where the base64 output should be written
|
||||
* @param buff_size Size of the output buffer
|
||||
*
|
||||
* @returns 1 in success and 0 in failure
|
||||
*/
|
||||
_nica_public_ int nc_b64enc_filename(const char *filename, char *buff, size_t buff_size);
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* This program is part of the Clear Linux Project
|
||||
*
|
||||
* Copyright 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms and conditions 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 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <getopt.h>
|
||||
#include "common.h"
|
||||
#include "telemetry.h"
|
||||
#include "nica/b64enc.h"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
static const char bert_record_file[] = "/sys/firmware/acpi/tables/data/BERT";
|
||||
static const char telem_record_class[] = "org.clearlinux/bert/debug";
|
||||
static uint32_t severity = 2;
|
||||
static uint32_t payload_version = 1;
|
||||
|
||||
void print_usage(char *prog)
|
||||
{
|
||||
printf("%s: Usage\n", prog);
|
||||
printf(" -f, --config_file Specify a configuration file other than default\n");
|
||||
printf(" -h, --help Display this help message\n");
|
||||
printf(" -V, --version Print the program version\n");
|
||||
}
|
||||
|
||||
static int allocate_payload_buffer(char **payload)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
*payload = (char *)malloc(MAX_PAYLOAD_SIZE);
|
||||
|
||||
if (*payload == NULL) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
*payload = memset(*payload, 0, MAX_PAYLOAD_SIZE);
|
||||
ret = 1;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct telem_ref *tm_handle = NULL;
|
||||
char *classification = (char *)telem_record_class;
|
||||
char *payload = NULL;
|
||||
|
||||
// Following vars are for arg parsing.
|
||||
int c;
|
||||
char *cfile = NULL;
|
||||
int opt_index = 0;
|
||||
int ret = 0;
|
||||
|
||||
struct option opts[] = {
|
||||
{ "config_file", 1, NULL, 'f' },
|
||||
{ "help", 0, NULL, 'h' },
|
||||
{ "version", 0, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
while ((c = getopt_long(argc, argv, "f:hHV", opts, &opt_index)) != -1) {
|
||||
switch (c) {
|
||||
case 'f':
|
||||
if (asprintf(&cfile, "%s", (char *)optarg) < 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
struct stat buf;
|
||||
ret = stat(cfile, &buf);
|
||||
|
||||
/* check if the file exists and is a regular file */
|
||||
if (ret == -1 || !S_ISREG(buf.st_mode)) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
tm_set_config_file(cfile);
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'V':
|
||||
printf(PACKAGE_VERSION "\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
case '?':
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!(ret = allocate_payload_buffer(&payload))) {
|
||||
printf("Unable to allocate more memory.\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!(ret = nc_b64enc_filename(bert_record_file, payload, MAX_PAYLOAD_SIZE))) {
|
||||
printf("Failed to read payload from: %s\n", bert_record_file);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((ret = tm_create_record(&tm_handle, severity, classification,
|
||||
payload_version)) < 0) {
|
||||
printf("Failed to create record: %s\n", strerror(-ret));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((ret = tm_set_payload(tm_handle, payload)) < 0) {
|
||||
printf("Failed to set record payload: %s\n", strerror(-ret));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
free(payload);
|
||||
|
||||
if ((ret = tm_send_record(tm_handle)) < 0) {
|
||||
printf("Failed to send record to daemon: %s\n", strerror(-ret));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
fail:
|
||||
free(cfile);
|
||||
tm_free_record(tm_handle);
|
||||
tm_handle = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
|
||||
@@ -71,7 +71,6 @@ static char unknown_class[30] = "org.clearlinux/crash/unknown";
|
||||
static char temp_core[] = "/tmp/corefile-XXXXXX";
|
||||
static bool keep_core = false;
|
||||
|
||||
|
||||
static const Dwfl_Callbacks cb =
|
||||
{
|
||||
.find_elf = dwfl_build_id_find_elf,
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ int main(int argc, char **argv)
|
||||
int ret = 0;
|
||||
|
||||
struct option opts[] = {
|
||||
{ "cfile", 1, NULL, 'f' },
|
||||
{ "config_file", 1, NULL, 'f' },
|
||||
{ "heartbeat", 0, NULL, 'H' },
|
||||
{ "help", 0, NULL, 'h' },
|
||||
{ "version", 0, NULL, 'V' },
|
||||
|
||||
+9
-1
@@ -5,7 +5,8 @@ bin_PROGRAMS += \
|
||||
%D%/klogscanner \
|
||||
%D%/pstoreprobe \
|
||||
%D%/oopsprobe \
|
||||
%D%/pstoreclean
|
||||
%D%/pstoreclean \
|
||||
%D%/bertprobe
|
||||
|
||||
%C%_hprobe_SOURCES = %D%/hello.c
|
||||
%C%_hprobe_LDADD = $(top_builddir)/src/libtelemetry.la
|
||||
@@ -13,6 +14,13 @@ bin_PROGRAMS += \
|
||||
$(AM_LDFLAGS) \
|
||||
-pie
|
||||
|
||||
%C%_bertprobe_SOURCES = %D%/bert_probe.c \
|
||||
src/nica/b64enc.c
|
||||
%C%_bertprobe_LDADD = $(top_builddir)/src/libtelemetry.la
|
||||
%C%_bertprobe_LDFLAGS = \
|
||||
$(AM_LDFLAGS) \
|
||||
-pie
|
||||
|
||||
%C%_telem_record_gen_SOURCES = %D%/telem_record_gen.c
|
||||
%C%_telem_record_gen_CFLAGS = \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
@@ -38,6 +38,7 @@ static char *opt_class = NULL;
|
||||
static char *opt_payload = NULL;
|
||||
static uint32_t payload_version = 1;
|
||||
static char *opt_payload_file = NULL;
|
||||
static char *opt_event_id = NULL;
|
||||
|
||||
static const struct option prog_opts[] = {
|
||||
{ "help", no_argument, 0, 'h' },
|
||||
@@ -48,6 +49,7 @@ static const struct option prog_opts[] = {
|
||||
{ "payload", required_argument, 0, 'p' },
|
||||
{ "payload-file", required_argument, 0, 'P' },
|
||||
{ "record-version", required_argument, 0, 'R' },
|
||||
{ "event-id", required_argument, 0, 'e' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -67,6 +69,7 @@ static void print_help(void)
|
||||
printf(" -p, --payload Record body (max size = 8k)\n");
|
||||
printf(" -P, --payload-file File to read payload from\n");
|
||||
printf(" -R, --record-version Version number for format of payload (default 1)\n");
|
||||
printf(" -e, --event-id Event id to use in the record\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
@@ -91,7 +94,7 @@ int parse_options(int argc, char **argv)
|
||||
long unsigned int tmp = 0;
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt_long(argc, argv, "hc:Vs:c:p:P:R:", prog_opts, NULL)) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, "hc:Vs:c:p:P:R:e:", prog_opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
print_help();
|
||||
@@ -140,6 +143,12 @@ int parse_options(int argc, char **argv)
|
||||
|
||||
payload_version = (uint32_t)tmp;
|
||||
break;
|
||||
case 'e':
|
||||
opt_event_id = strdup(optarg);
|
||||
if (opt_event_id == NULL) {
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,6 +161,7 @@ int validate_opts(void)
|
||||
{
|
||||
size_t len;
|
||||
int ret = 0;
|
||||
const char alphab[] = EVENT_ID_ALPHAB;
|
||||
|
||||
/* classification */
|
||||
if (opt_class == NULL) {
|
||||
@@ -187,6 +197,20 @@ int validate_opts(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Event id */
|
||||
if (opt_event_id) {
|
||||
size_t result = 0;
|
||||
if ((result = strlen(opt_event_id)) != EVENT_ID_LEN) {
|
||||
fprintf(stderr, "Error: event_id length %zu it should have %d characters\n", result, EVENT_ID_LEN);
|
||||
return ret;
|
||||
}
|
||||
if ((result = strspn(opt_event_id, alphab)) != EVENT_ID_LEN) {
|
||||
fprintf(stderr, "Error: event_id contains invalid character '%c' at position %zu, valid characters are %s\n",
|
||||
opt_event_id[result], result, alphab);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -308,6 +332,10 @@ int send_record(char *payload)
|
||||
goto out1;
|
||||
}
|
||||
|
||||
if (opt_event_id && tm_set_event_id(t_ref, opt_event_id) < 0) {
|
||||
goto out2;
|
||||
}
|
||||
|
||||
if (tm_set_payload(t_ref, payload) < 0) {
|
||||
goto out2;
|
||||
}
|
||||
@@ -348,6 +376,7 @@ fail:
|
||||
free(config_file);
|
||||
free(opt_class);
|
||||
free(opt_payload);
|
||||
free(opt_event_id);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* This program is part of the Clear Linux Project
|
||||
*
|
||||
* Copyright 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms and conditions 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 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "common.h"
|
||||
|
||||
int delete_record_by_id(char *record_id)
|
||||
{
|
||||
int ret = 0;
|
||||
char *record_path = NULL;
|
||||
|
||||
ret = asprintf(&record_path, "%s/%s", RECORD_RETENTION_DIR, record_id);
|
||||
if (ret == -1) {
|
||||
return 1;
|
||||
}
|
||||
ret = unlink(record_path);
|
||||
if (ret == -1) {
|
||||
telem_perror("Error deleting saved record");
|
||||
}
|
||||
free(record_path);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* This program is part of the Clear Linux Project
|
||||
*
|
||||
* Copyright 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms and conditions 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 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.
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
/**
|
||||
* Delete record identified by record unique id
|
||||
*
|
||||
* @param record_id Unique identifier of entry
|
||||
*
|
||||
*/
|
||||
int delete_record_by_id(char *record_id);
|
||||
|
||||
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
|
||||
+83
-43
@@ -27,12 +27,14 @@
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <malloc.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
#include "telemdaemon.h"
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
#include "configuration.h"
|
||||
#include "retention.h"
|
||||
|
||||
void initialize_daemon(TelemDaemon *daemon)
|
||||
{
|
||||
@@ -43,7 +45,9 @@ void initialize_daemon(TelemDaemon *daemon)
|
||||
daemon->client_head = head;
|
||||
daemon->bypass_http_post_ts = 0;
|
||||
daemon->is_spool_valid = false;
|
||||
daemon->record_journal = open_journal(JOURNAL_PATH);
|
||||
initialize_rate_limit(daemon);
|
||||
initialize_record_delivery(daemon);
|
||||
daemon->current_spool_size = 0;
|
||||
}
|
||||
|
||||
@@ -61,6 +65,12 @@ void initialize_rate_limit(TelemDaemon *daemon)
|
||||
daemon->rate_limit_strategy = rate_limit_strategy_config();
|
||||
}
|
||||
|
||||
void initialize_record_delivery(TelemDaemon *daemon)
|
||||
{
|
||||
daemon->record_retention_enabled = record_retention_enabled_config();
|
||||
daemon->record_server_delivery_enabled = record_server_delivery_enabled_config();
|
||||
}
|
||||
|
||||
client *add_client(client_list_head *client_head, int fd)
|
||||
{
|
||||
client *cl;
|
||||
@@ -262,6 +272,21 @@ void machine_id_replace(char **machine_header, char *machine_id_override)
|
||||
free(old_header);
|
||||
}
|
||||
|
||||
void save_entry_to_journal(TelemDaemon *daemon, time_t t_stamp, char *headers[])
|
||||
{
|
||||
char *classification_value;
|
||||
char *event_id_value;
|
||||
|
||||
if (get_header_value(headers[TM_CLASSIFICATION], &classification_value) &&
|
||||
get_header_value(headers[TM_EVENT_ID], &event_id_value)) {
|
||||
if (new_journal_entry(daemon->record_journal, classification_value, t_stamp, event_id_value) != 0) {
|
||||
telem_log(LOG_INFO, "new_journal_entry in process_record: failed saving record entry\n");
|
||||
}
|
||||
}
|
||||
free(classification_value);
|
||||
free(event_id_value);
|
||||
}
|
||||
|
||||
void process_record(TelemDaemon *daemon, client *cl)
|
||||
{
|
||||
int i = 0;
|
||||
@@ -279,7 +304,6 @@ void process_record(TelemDaemon *daemon, client *cl)
|
||||
bool byte_check_passed = true;
|
||||
bool record_burst_enabled = true;
|
||||
bool byte_burst_enabled = true;
|
||||
|
||||
/* Gets the current minute of time */
|
||||
time_t temp = time(NULL);
|
||||
struct tm *tm_s = localtime(&temp);
|
||||
@@ -311,6 +335,22 @@ void process_record(TelemDaemon *daemon, client *cl)
|
||||
/* TODO : check if the body is within the limits. */
|
||||
body = msg + header_size;
|
||||
|
||||
/* Save record in journal */
|
||||
save_entry_to_journal(daemon, temp, headers);
|
||||
|
||||
/* Save local copy */
|
||||
if (daemon->record_retention_enabled) {
|
||||
save_local_copy(daemon, body);
|
||||
}
|
||||
|
||||
/* Bail out if server delivery is not enabled */
|
||||
if (!daemon->record_server_delivery_enabled) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stdout, "process_record: record server delivery disabled\n");
|
||||
#endif
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (inside_direct_spool_window(daemon, time(NULL))) {
|
||||
telem_log(LOG_INFO, "process_record: delivering directly to spool\n");
|
||||
spool_record(daemon, headers, body);
|
||||
@@ -342,12 +382,12 @@ void process_record(TelemDaemon *daemon, client *cl)
|
||||
daemon->rate_limit_enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Sends record if rate limiting is disabled, or all checks passed */
|
||||
if (!daemon->rate_limit_enabled || (record_check_passed && byte_check_passed)) {
|
||||
/* Send the record as https post */
|
||||
record_sent = post_record_ptr(headers, body, true);
|
||||
}
|
||||
|
||||
// Get rate-limit strategy
|
||||
do_spool = spool_strategy_selected(daemon);
|
||||
|
||||
@@ -543,6 +583,39 @@ bool post_record_http(char *headers[], char *body, bool spool)
|
||||
return res ? false : true;
|
||||
}
|
||||
|
||||
void save_local_copy(TelemDaemon *daemon, char *body)
|
||||
{
|
||||
int ret = 0;
|
||||
char *tmpbuf = NULL;
|
||||
FILE *tmpfile = NULL;
|
||||
|
||||
if (daemon == NULL || daemon->record_journal == NULL ||
|
||||
daemon->record_journal->latest_record_id == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
ret = asprintf(&tmpbuf, "%s/%s", RECORD_RETENTION_DIR,
|
||||
daemon->record_journal->latest_record_id);
|
||||
if (ret == -1) {
|
||||
telem_log(LOG_ERR, "Failed to allocate memory for record full path, aborting\n");
|
||||
return;
|
||||
}
|
||||
|
||||
tmpfile = fopen(tmpbuf, "w");
|
||||
if (!tmpfile) {
|
||||
telem_perror("Error opening local record copy temp file");
|
||||
goto save_err;
|
||||
}
|
||||
|
||||
// Save body
|
||||
fprintf(tmpfile, "%s\n", body);
|
||||
fclose(tmpfile);
|
||||
|
||||
save_err:
|
||||
free(tmpbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
void spool_record(TelemDaemon *daemon, char *headers[], char *body)
|
||||
{
|
||||
int ret = 0;
|
||||
@@ -584,7 +657,6 @@ void spool_record(TelemDaemon *daemon, char *headers[], char *body)
|
||||
goto spool_err;
|
||||
}
|
||||
|
||||
//fp = fopen(spool_dir_path, const char *mode);
|
||||
tmpfile = fdopen(tmpfd, "a");
|
||||
if (!tmpfile) {
|
||||
telem_perror("Error opening temp file");
|
||||
@@ -679,7 +751,7 @@ bool get_machine_id(char *machine_id)
|
||||
return true;
|
||||
}
|
||||
|
||||
int machine_id_write(uint64_t upper, uint64_t lower)
|
||||
int machine_id_write(char *new_id)
|
||||
{
|
||||
FILE *fp;
|
||||
int ret = 0;
|
||||
@@ -691,7 +763,7 @@ int machine_id_write(uint64_t upper, uint64_t lower)
|
||||
goto file_error;
|
||||
}
|
||||
|
||||
ret = fprintf(fp, "%.16" PRIx64 "%.16" PRIx64, upper, lower);
|
||||
ret = fprintf(fp, "%s", new_id);
|
||||
if (ret < 0) {
|
||||
telem_perror("Unable to write to machine id file");
|
||||
goto file_error;
|
||||
@@ -708,49 +780,17 @@ file_error:
|
||||
|
||||
int generate_machine_id(void)
|
||||
{
|
||||
int frandom = -1;
|
||||
struct stat stat_buf;
|
||||
int ret = 0;
|
||||
struct iovec random_id[2];
|
||||
uint64_t random_id_upper;
|
||||
uint64_t random_id_lower;
|
||||
int result = -1;
|
||||
int result = 0;
|
||||
char *new_id = NULL;
|
||||
|
||||
ret = stat("/dev/urandom", &stat_buf);
|
||||
if (ret == -1) {
|
||||
telem_log(LOG_ERR, "Unable to stat urandom device\n");
|
||||
if ((result = get_random_id(&new_id)) != 0) {
|
||||
goto rand_err;
|
||||
}
|
||||
|
||||
if (!S_ISCHR(stat_buf.st_mode)) {
|
||||
telem_log(LOG_ERR, "/dev/urandom is not a character device file\n");
|
||||
goto rand_err;
|
||||
}
|
||||
|
||||
/* TODO : check for major and minor numbers to be extra sure ??
|
||||
((stat_buffer.st_rdev == makedev(1, 8)) || (stat_buffer.st_rdev == makedev(1, 9))*/
|
||||
|
||||
frandom = open("/dev/urandom", O_RDONLY);
|
||||
if (frandom < 0) {
|
||||
telem_perror("Error opening /dev/urandom");
|
||||
goto rand_err;
|
||||
}
|
||||
|
||||
random_id[0].iov_base = &random_id_upper;
|
||||
random_id[0].iov_len = 8;
|
||||
random_id[1].iov_base = &random_id_lower;
|
||||
random_id[1].iov_len = 8;
|
||||
|
||||
if (readv(frandom, random_id, 2) < 0) {
|
||||
telem_perror("Error while reading /dev/urandom");
|
||||
goto rand_err;
|
||||
}
|
||||
|
||||
result = machine_id_write(random_id_upper, random_id_lower);
|
||||
result = machine_id_write(new_id);
|
||||
rand_err:
|
||||
if (frandom >= 0) {
|
||||
close(frandom);
|
||||
}
|
||||
free(new_id);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
+24
-4
@@ -22,6 +22,7 @@
|
||||
#include <sys/queue.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
#include "journal/journal.h"
|
||||
|
||||
#define TM_MACHINE_ID_EXPIRY (3 /*d*/ * 24 /*h*/ * 60 /*m*/ * 60 /*s*/)
|
||||
|
||||
@@ -56,7 +57,8 @@ typedef struct TelemDaemon {
|
||||
client_list_head client_head;
|
||||
/* Time of last failed post */
|
||||
time_t bypass_http_post_ts;
|
||||
|
||||
/* Telemetry Journal*/
|
||||
TelemJournal *record_journal;
|
||||
/* Rate limit record and byte arrays */
|
||||
size_t record_burst_array[TM_RATE_LIMIT_SLOTS];
|
||||
size_t byte_burst_array[TM_RATE_LIMIT_SLOTS];
|
||||
@@ -67,10 +69,12 @@ typedef struct TelemDaemon {
|
||||
int64_t byte_burst_limit;
|
||||
int byte_window_length;
|
||||
const char *rate_limit_strategy;
|
||||
|
||||
/* Spool configuration */
|
||||
bool is_spool_valid;
|
||||
long current_spool_size;
|
||||
|
||||
/* Record local copy and delivery */
|
||||
bool record_retention_enabled;
|
||||
bool record_server_delivery_enabled;
|
||||
char *machine_id_override;
|
||||
} TelemDaemon;
|
||||
|
||||
@@ -88,6 +92,14 @@ void initialize_daemon(TelemDaemon *daemon);
|
||||
*/
|
||||
void initialize_rate_limit(TelemDaemon *daemon);
|
||||
|
||||
/**
|
||||
* Initialize record delivery to remote and locally
|
||||
* in the daemon
|
||||
*
|
||||
* @param daemon A pointer to the daemon structure
|
||||
*/
|
||||
void initialize_record_delivery(TelemDaemon *daemon);
|
||||
|
||||
/**
|
||||
* Add poll fd struct to the array of pollfds.
|
||||
*
|
||||
@@ -267,7 +279,15 @@ bool post_record_http(char *header_values[], char *body, bool spool);
|
||||
* @param body The payload of the record
|
||||
*
|
||||
*/
|
||||
void spool_record(TelemDaemon *daemon, char *headers[], char *body);
|
||||
void spool_record(TelemDaemon * daemon, char *headers[], char *body);
|
||||
|
||||
/**
|
||||
* Save a copy of the record payload locally
|
||||
*
|
||||
* @param body The payload of the record
|
||||
*
|
||||
*/
|
||||
void save_local_copy(TelemDaemon *daemon, char *body);
|
||||
|
||||
/**
|
||||
* Get random machine id stored in file
|
||||
|
||||
+247
-25
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -30,6 +31,7 @@
|
||||
#include <inttypes.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#include "util.h"
|
||||
#include "common.h"
|
||||
#include "configuration.h"
|
||||
#include "telemetry.h"
|
||||
@@ -137,38 +139,14 @@ static int set_severity_header(struct telem_ref *t_ref, uint32_t severity)
|
||||
*/
|
||||
static int set_classification_header(struct telem_ref *t_ref, char *classification)
|
||||
{
|
||||
size_t i, j;
|
||||
int slashes = 0;
|
||||
int x = 0;
|
||||
|
||||
j = strlen(classification);
|
||||
|
||||
if (j > MAX_CLASS_LENGTH) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
for (i = 0, x = 0; i <= (j - 1); i++, x++) {
|
||||
if (classification[i] == '/') {
|
||||
slashes++;
|
||||
x = 0;
|
||||
} else {
|
||||
if (x > MAX_SUBCAT_LENGTH) {
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (slashes != 2) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "ERR: Classification string should have two /s.\n");
|
||||
#endif
|
||||
if (validate_classification(classification) == 1) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return set_header(&(t_ref->record->headers[TM_CLASSIFICATION]),
|
||||
TM_CLASSIFICATION_STR, classification,
|
||||
&(t_ref->record->header_size));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -400,6 +378,62 @@ static int set_timestamp_header(struct telem_ref *t_ref)
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets cpu model for telemetry record. The information from cpu is extracted
|
||||
* from /proc/cpuinfo, specifically "model name" attribute.
|
||||
*
|
||||
* @param t_ref Telemetry Record reference obtained from tm_create_record.
|
||||
*
|
||||
* @return 0 if successful, or a negative errno-style value if not.
|
||||
*
|
||||
*/
|
||||
static int set_cpu_model_header(struct telem_ref *t_ref)
|
||||
{
|
||||
FILE *fs = NULL;
|
||||
char buf[SMALL_LINE_BUF] = { 0 };
|
||||
char *model_name = NULL;
|
||||
const char *attr_name = "model name";
|
||||
int status = 0;
|
||||
size_t attr_len = strlen(attr_name);
|
||||
size_t model_str_len = 0;
|
||||
|
||||
fs = fopen("/proc/cpuinfo", "r");
|
||||
if (fs != NULL) {
|
||||
while (fgets(buf, SMALL_LINE_BUF, fs)) {
|
||||
if (strncmp(attr_name, buf, attr_len) == 0) {
|
||||
model_name = strchr(buf, ':');
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fs);
|
||||
if (model_name != NULL) {
|
||||
model_str_len = strlen(model_name);
|
||||
if (model_str_len > 2) {
|
||||
model_name = (char *)model_name + 2 * sizeof(char);
|
||||
model_name[model_str_len - 2] = '\0';
|
||||
} else {
|
||||
model_name = "blank";
|
||||
}
|
||||
} else {
|
||||
model_name = "blank";
|
||||
fprintf(stderr, "NOTICE: Unable to find attribute:%s\n", attr_name);
|
||||
}
|
||||
|
||||
status = set_header(
|
||||
&(t_ref->record->headers[TM_CPU_MODEL]),
|
||||
TM_CPU_MODEL_STR, model_name,
|
||||
&(t_ref->record->header_size));
|
||||
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "NOTICE: Unable to open /proc/cpuinfo\n");
|
||||
#endif
|
||||
status = -1;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* A healper function for set_host_type_header that reads the first line out of
|
||||
* a file and chomps the newline if necessary. If the file does not exist the
|
||||
@@ -497,6 +531,118 @@ static int get_dmi_value(const char *source, const char *key, char **buf)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the board name for telemetry record, this record is a combination of
|
||||
* board name and board vendor. This information is read from dmi filesystem
|
||||
* Board Name (board_name) and Board Vendor (board_vendor).
|
||||
*
|
||||
* @param t_ref Telemetry Record reference obtained from tm_create_record.
|
||||
*
|
||||
* @return 0 if successful, or a negative errno-style value if not.
|
||||
*
|
||||
*/
|
||||
static int set_board_name_header(struct telem_ref *t_ref)
|
||||
{
|
||||
int status = 0;
|
||||
int rc;
|
||||
char *buf = NULL;
|
||||
char *bn = NULL;
|
||||
char *bv = NULL;
|
||||
|
||||
rc = get_dmi_value("/sys/class/dmi/id/board_name", "bn", &bn);
|
||||
if (rc < 0) {
|
||||
status = rc;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = get_dmi_value("/sys/class/dmi/id/board_vendor", "bv", &bv);
|
||||
if (rc < 0) {
|
||||
status = rc;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
rc = asprintf(&buf, "%s|%s", bn, bv);
|
||||
|
||||
if (rc < 0) {
|
||||
status = -ENOMEM;
|
||||
goto cleanup;
|
||||
} else {
|
||||
status = set_header(
|
||||
&(t_ref->record->headers[TM_BOARD_NAME]),
|
||||
TM_BOARD_NAME_STR, buf,
|
||||
&(t_ref->record->header_size));
|
||||
free(buf);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
if (bn != NULL) {
|
||||
free(bn);
|
||||
}
|
||||
|
||||
if (bv != NULL) {
|
||||
free(bv);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets BIOS version header for telemetry record, this information is
|
||||
* read from dmi filesystem BIOS Version (bios_version).
|
||||
*
|
||||
* @param t_ref Telemetry Record reference obtained from tm_create_record.
|
||||
*
|
||||
* @return 0 if successful, or a negative errno-style value if not.
|
||||
*
|
||||
*/
|
||||
static int set_bios_version_header(struct telem_ref *t_ref)
|
||||
{
|
||||
int status = 0;
|
||||
int rc = 0;
|
||||
char *bios_version = NULL;
|
||||
|
||||
rc = get_dmi_value("/sys/class/dmi/id/bios_version", "bv", &bios_version);
|
||||
if (rc < 0) {
|
||||
status = rc;
|
||||
} else {
|
||||
status = set_header(
|
||||
&(t_ref->record->headers[TM_BIOS_VERSION]),
|
||||
TM_BIOS_VERSION_STR, bios_version,
|
||||
&(t_ref->record->header_size));
|
||||
free(bios_version);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the event_id header, this id is an identifier that multiple
|
||||
* records can share. This means that one event can lead to multiple
|
||||
* records.
|
||||
*
|
||||
* @param t_ref Telemetry Record reference obtained from tm_create_record.
|
||||
*
|
||||
* @return 0 if successful, -1 on failure
|
||||
*
|
||||
*/
|
||||
static int set_event_id_header(struct telem_ref *t_ref)
|
||||
{
|
||||
int rc = 0;
|
||||
char *buff = NULL;
|
||||
|
||||
rc = get_random_id(&buff);
|
||||
|
||||
if (rc == 0) {
|
||||
rc = set_header(
|
||||
&(t_ref->record->headers[TM_EVENT_ID]),
|
||||
TM_EVENT_ID_STR, buff,
|
||||
&(t_ref->record->header_size));
|
||||
}
|
||||
free(buff);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the hosttype header, which is a tuple of three values looked for
|
||||
* in the dmi filesystem. System Vendor (sys_vendor), Product Name
|
||||
@@ -730,6 +876,30 @@ int allocate_header(struct telem_ref *t_ref, uint32_t severity,
|
||||
goto free_and_fail;
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
if ((ret = set_board_name_header(t_ref)) < 0) {
|
||||
goto free_and_fail;
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
if ((ret = set_cpu_model_header(t_ref)) < 0) {
|
||||
goto free_and_fail;
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
if ((ret = set_bios_version_header(t_ref)) < 0) {
|
||||
goto free_and_fail;
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
if ((ret = set_event_id_header(t_ref)) < 0) {
|
||||
goto free_and_fail;
|
||||
}
|
||||
|
||||
i++; /* Not necessary, but including for future expansion */
|
||||
|
||||
return ret;
|
||||
@@ -858,6 +1028,58 @@ int tm_set_payload(struct telem_ref *t_ref, char *payload)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for id to have length = 32 characters
|
||||
* and hexadecimal characters only.
|
||||
*
|
||||
* @param id A pointer to string to be checked
|
||||
*
|
||||
* @return 0 on success, 1 on failure
|
||||
*
|
||||
*/
|
||||
static int validate_event_id(char *id)
|
||||
{
|
||||
int rc = 0;
|
||||
const char alphab[] = EVENT_ID_ALPHAB;
|
||||
|
||||
// make sure is not null
|
||||
if (!id) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// 32 - 32 = 0
|
||||
if ((rc = (int)(strlen(id) - EVENT_ID_LEN)) != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// verify alphabet
|
||||
// strspn checks for characters in alphab
|
||||
if (strspn(id, alphab) != EVENT_ID_LEN) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int tm_set_event_id(struct telem_ref *t_ref, char *event_id)
|
||||
{
|
||||
int rc = -1;
|
||||
|
||||
if (!validate_event_id(event_id)) {
|
||||
if (t_ref && t_ref->record && t_ref->record->headers) {
|
||||
// free default id before overriding
|
||||
free(t_ref->record->headers[TM_EVENT_ID]);
|
||||
// set new event_id
|
||||
if (asprintf(&(t_ref->record->headers[TM_EVENT_ID]),
|
||||
"%s: %s\n", TM_EVENT_ID_STR, event_id) > 0) {
|
||||
rc = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write nbytes from buf to fd. Used to send records to telemd.
|
||||
*
|
||||
|
||||
@@ -85,6 +85,19 @@ void tm_set_config_file(char *c_file);
|
||||
int tm_create_record(struct telem_ref **t_ref, uint32_t severity,
|
||||
char *classification, uint32_t payload_version);
|
||||
|
||||
/**
|
||||
* Sets the event_id to a user defined id
|
||||
*
|
||||
* @param t_ref A pointer to a telem_ref struct that was previously initialized
|
||||
* this struct will have an event_id already initialized and it will be
|
||||
* overriden by a user provided event_id
|
||||
* @param event_id A pointer to a string that contains the 32 character length
|
||||
* event_id
|
||||
*
|
||||
* @return 0 on success, or a negative errno-style value on error
|
||||
*/
|
||||
int tm_set_event_id(struct telem_ref *t_ref, char *event_id);
|
||||
|
||||
/**
|
||||
* Set the payload field of a telemetrics record
|
||||
*
|
||||
|
||||
@@ -16,3 +16,8 @@ TM_3_0_0 {
|
||||
tm_set_payload;
|
||||
tm_send_record;
|
||||
} TM_2_0_0;
|
||||
|
||||
TM_4_0_0 {
|
||||
global:
|
||||
tm_set_event_id;
|
||||
} TM_3_0_0;
|
||||
|
||||
+104
@@ -16,16 +16,22 @@
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#define RANDOM_ID_LEN 32
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
|
||||
bool get_header(const char *haystack, const char *needle, char **line, size_t len)
|
||||
@@ -37,6 +43,28 @@ bool get_header(const char *haystack, const char *needle, char **line, size_t le
|
||||
return false;
|
||||
}
|
||||
|
||||
bool get_header_value(const char *header, char **value)
|
||||
{
|
||||
char *sep = NULL;
|
||||
|
||||
*value = NULL;
|
||||
|
||||
if (header == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((sep = strchr(header, ':')) != NULL) {
|
||||
sep++;
|
||||
// skip space after colon if there's one
|
||||
if (*sep == ' ') {
|
||||
sep++;
|
||||
}
|
||||
*value = strdup(sep);
|
||||
}
|
||||
|
||||
return (bool)(value != NULL);
|
||||
}
|
||||
|
||||
void *reallocate(void **addr, size_t *allocated, size_t requested)
|
||||
{
|
||||
void *newaddr;
|
||||
@@ -107,4 +135,80 @@ long get_directory_size(const char *dir_path)
|
||||
return total_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a 32 characters random id
|
||||
*
|
||||
* @param buffer pointer to allocate and copy data
|
||||
*
|
||||
*/
|
||||
int get_random_id(char **buff)
|
||||
{
|
||||
int result = -1;
|
||||
int frandom = -1;
|
||||
uint64_t random_id[2] = { '\0' };
|
||||
|
||||
frandom = open("/dev/urandom", O_RDONLY);
|
||||
if (frandom < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (read(frandom, &random_id, sizeof(random_id)) == sizeof(random_id)) {
|
||||
if (asprintf(buff, "%.16" PRIx64 "%.16" PRIx64, random_id[0], random_id[1]) == RANDOM_ID_LEN) {
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
|
||||
close(frandom);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate classification value. A valid classification
|
||||
* is a string with 2 slashes, with max length of
|
||||
* MAX_CLASS_LENGTH and strings betweeb slashes should
|
||||
* have a max length of MAX_SUBCAT_LENGTH.
|
||||
*
|
||||
* @param classification A pointer to classification value
|
||||
* to be validated.
|
||||
*
|
||||
* @return 0 on sucess and 1 on failure
|
||||
*/
|
||||
int validate_classification(char *classification)
|
||||
{
|
||||
size_t i, j;
|
||||
int slashes = 0;
|
||||
int x = 0;
|
||||
|
||||
if (classification == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
j = strlen(classification);
|
||||
|
||||
if (j > MAX_CLASS_LENGTH) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
for (i = 0, x = 0; i <= (j - 1); i++, x++) {
|
||||
if (classification[i] == '/') {
|
||||
slashes++;
|
||||
x = 0;
|
||||
} else {
|
||||
if (x > MAX_SUBCAT_LENGTH) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (slashes != 2) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "ERR: Classification string should have two /s.\n");
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
|
||||
|
||||
@@ -24,7 +24,16 @@ void *reallocate(void **addr, size_t *allocated, size_t requested);
|
||||
/* Check if haystacks begins with needle and return a copy of haystack */
|
||||
bool get_header(const char *haystack, const char *needle, char **line, size_t len);
|
||||
|
||||
/* Get the value of a header */
|
||||
bool get_header_value(const char *header, char **value);
|
||||
|
||||
/* Get the size of the directory */
|
||||
long get_directory_size(const char *sdir);
|
||||
|
||||
/* Initialize buff and copy generated id */
|
||||
int get_random_id(char **buff);
|
||||
|
||||
/* Validates classification value */
|
||||
int validate_classification(char *classification);
|
||||
|
||||
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
|
||||
|
||||
@@ -55,6 +55,34 @@ START_TEST(check_read_valid_config)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_read_valid_config_defaults)
|
||||
{
|
||||
char *config_file = TOPSRCDIR "/src/data/example.conf";
|
||||
configuration config = { { 0 }, { 0 }, { 0 }, false, NULL };
|
||||
|
||||
int ret = read_config_from_file(config_file, &config);
|
||||
ck_assert(ret == true);
|
||||
|
||||
// RECORD_RETENTION_ENABLED_DEFAULT = false
|
||||
ck_assert(config.boolValues[CONF_RECORD_RETENTION_ENABLED] == RECORD_RETENTION_ENABLED_DEFAULT);
|
||||
// RECORD_SERVER_DELIVERY_ENABLED_DEFAULT = true
|
||||
ck_assert(config.boolValues[CONF_RECORD_SERVER_DELIVERY_ENABLED] == RECORD_SERVER_DELIVERY_ENABLED_DEFAULT);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_read_valid_config_record_retention_delivery)
|
||||
{
|
||||
char *config_file = TOPSRCDIR "/src/data/example.1.conf";
|
||||
configuration config = { { 0 }, { 0 }, { 0 }, false, NULL };
|
||||
|
||||
int ret = read_config_from_file(config_file, &config);
|
||||
ck_assert(ret == true);
|
||||
|
||||
ck_assert(config.boolValues[CONF_RECORD_RETENTION_ENABLED] == true);
|
||||
ck_assert(config.boolValues[CONF_RECORD_SERVER_DELIVERY_ENABLED] == false);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_config_initialised)
|
||||
{
|
||||
char *config_file = ABSTOPSRCDIR "/src/data/example.conf";
|
||||
@@ -89,6 +117,8 @@ Suite *config_suite(void)
|
||||
TCase *t = tcase_create("config");
|
||||
tcase_add_test(t, check_read_config_for_invalid_file);
|
||||
tcase_add_test(t, check_read_valid_config);
|
||||
tcase_add_test(t, check_read_valid_config_defaults);
|
||||
tcase_add_test(t, check_read_valid_config_record_retention_delivery);
|
||||
tcase_add_test(t, check_config_initialised);
|
||||
|
||||
// add more TCases here
|
||||
|
||||
@@ -295,7 +295,11 @@ START_TEST(check_process_record_with_correct_size_and_data)
|
||||
"machine_id: 1234\ncreation_timestamp: 1418672344\narch:x86_64\n"
|
||||
"host_type: macbookpro\nbuild: 200\nkernel_version: 3.15\n"
|
||||
"payload_format_version: 1\n"
|
||||
"system_name: clear-linux-os\n";
|
||||
"system_name: clear-linux-os\n"
|
||||
"board_name: Qemu|Intel\n"
|
||||
"cpu_model: Intel(R) Core(TM) i7-5650U CPU @ 2.20GHz\n"
|
||||
"bios_version: Qemu\n"
|
||||
"event_id: 3a2d799826edc6266d72824d2aac6763\n";
|
||||
char *post_body = "test message";
|
||||
|
||||
set_up_socket_pair(&client_fd, &server_fd);
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* This program is part of the Clear Linux Project
|
||||
*
|
||||
* Copyright 2018 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms and conditions 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 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.
|
||||
*/
|
||||
|
||||
#include <check.h>
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include "common.h"
|
||||
#include "journal/journal.h"
|
||||
|
||||
static struct TelemJournal *journal = NULL;
|
||||
static char *journal_file = TESTOOPSDIR "/journal.txt";
|
||||
static char *eid = "00007766547776eb7fc478eb0eb43e43";
|
||||
static int K = 20;
|
||||
|
||||
START_TEST(check_open_journal)
|
||||
{
|
||||
struct TelemJournal *j = open_journal(journal_file);
|
||||
ck_assert_ptr_nonnull(j);
|
||||
ck_assert_ptr_nonnull(j->fptr);
|
||||
ck_assert_ptr_nonnull(j->boot_id);
|
||||
ck_assert_int_eq(j->record_count, 0);
|
||||
close_journal(j);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_unsuccessful_open_journal)
|
||||
{
|
||||
char *bad_journal_file = "/sys/firmware/acpi/tables/journal";
|
||||
struct TelemJournal *j = open_journal(bad_journal_file);
|
||||
ck_assert_ptr_null(j);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void new_entry_setup(void)
|
||||
{
|
||||
if (journal) {
|
||||
return;
|
||||
}
|
||||
|
||||
journal = open_journal(journal_file);
|
||||
}
|
||||
|
||||
START_TEST(check_new_entry)
|
||||
{
|
||||
int ret;
|
||||
ret = new_journal_entry(journal, "t/t/t", 1520054957,
|
||||
"3bc17766547776eb7fc478eb0eb43e43");
|
||||
ck_assert_int_eq(ret, 0);
|
||||
close_journal(journal);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_new_entry_bad_class)
|
||||
{
|
||||
int ret = 0;
|
||||
/* has an invalid class */
|
||||
ret = new_journal_entry(journal, "t/t", 1520054957,
|
||||
"3bc17766547776eb7fc478eb0eb43e43");
|
||||
ck_assert_int_eq(ret, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_new_entry_bad_id)
|
||||
{
|
||||
int ret = 0;
|
||||
/* event_id is invalid */
|
||||
ret = new_journal_entry(journal, "t/t/t", 1520054957,
|
||||
"Xbc17766547776eb7fc478eb0eb43e43");
|
||||
ck_assert_int_eq(ret, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_new_entry_null_class)
|
||||
{
|
||||
int ret = 0;
|
||||
/* param is NULL */
|
||||
ret = new_journal_entry(journal, NULL, 1520054957,
|
||||
"3bc17766547776eb7fc478eb0eb43e43");
|
||||
ck_assert_int_eq(ret, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_new_entry_null_id)
|
||||
{
|
||||
int ret = 0;
|
||||
/* null id */
|
||||
ret = new_journal_entry(journal, "t/t/t", 1520054957, NULL);
|
||||
ck_assert_int_eq(ret, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void new_entry_teardown(void)
|
||||
{
|
||||
if (journal) {
|
||||
close_journal(journal);
|
||||
journal = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void insert_n_records(int n, struct TelemJournal *j)
|
||||
{
|
||||
for (int i = 0; i < n; i++) {
|
||||
new_journal_entry(j, "t/t/t", 1520054957 + i,
|
||||
"3bc17766547776eb7fc478eb0eb43e43");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
failing in travis-ci
|
||||
*/
|
||||
START_TEST(check_journal_file_prune)
|
||||
{
|
||||
int rc = 0;
|
||||
struct TelemJournal *j = open_journal(journal_file);
|
||||
|
||||
insert_n_records(j->record_count_limit * 2, j);
|
||||
ck_assert_int_gt(j->record_count, j->record_count_limit);
|
||||
rc = prune_journal(j, TESTOOPSDIR);
|
||||
ck_assert(rc == 0);
|
||||
// Record count should always be below the limit + hysteresis
|
||||
ck_assert_int_lt(j->record_count, j->record_count_limit + DEVIATION);
|
||||
close_journal(j);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void journal_entry_setup(void)
|
||||
{
|
||||
int result = 0;
|
||||
const char *journal_print = TESTOOPSDIR "/journal.print.txt";
|
||||
|
||||
if (journal) {
|
||||
close_journal(journal);
|
||||
}
|
||||
|
||||
journal = open_journal(journal_print);
|
||||
|
||||
insert_n_records(K, journal);
|
||||
/* Insert recors with specific values */
|
||||
result = new_journal_entry(journal, "a/b/c", 1520054957, eid);
|
||||
ck_assert(result == 0);
|
||||
result = new_journal_entry(journal, "a/b/d", 1520054957, eid);
|
||||
ck_assert(result == 0);
|
||||
|
||||
}
|
||||
|
||||
START_TEST(check_journal_print)
|
||||
{
|
||||
int count = 0;
|
||||
count = print_journal(journal, NULL, NULL, NULL, NULL, 0);
|
||||
ck_assert_int_eq(count, K + 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_journal_filter_by_class)
|
||||
{
|
||||
int result = print_journal(journal, "a/b/c", NULL, NULL, NULL, 0);
|
||||
ck_assert_int_eq(result, 1);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_journal_filter_by_class_prefix)
|
||||
{
|
||||
int result = print_journal(journal, "a/b/*", NULL, NULL, NULL, 0);
|
||||
ck_assert_int_eq(result, 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_journal_filter_by_event_id)
|
||||
{
|
||||
int result = print_journal(journal, NULL, NULL, eid, NULL, 0);
|
||||
ck_assert(result == 2);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void journal_entry_teardown(void)
|
||||
{
|
||||
close_journal(journal);
|
||||
}
|
||||
|
||||
Suite *config_suite(void)
|
||||
{
|
||||
// A suite is comprised of test cases, defined below
|
||||
Suite *s = suite_create("journal_feature");
|
||||
|
||||
// Individual unit tests are added to "test cases"
|
||||
TCase *t = tcase_create("journal");
|
||||
tcase_add_test(t, check_open_journal);
|
||||
tcase_add_test(t, check_unsuccessful_open_journal);
|
||||
suite_add_tcase(s, t);
|
||||
|
||||
t = tcase_create("new entry");
|
||||
tcase_add_unchecked_fixture(t, new_entry_setup, new_entry_teardown);
|
||||
tcase_add_test(t, check_new_entry);
|
||||
tcase_add_test(t, check_new_entry_bad_class);
|
||||
tcase_add_test(t, check_new_entry_bad_id);
|
||||
tcase_add_test(t, check_new_entry_null_class);
|
||||
tcase_add_test(t, check_new_entry_null_id);
|
||||
suite_add_tcase(s, t);
|
||||
|
||||
t = tcase_create("prunning journal");
|
||||
tcase_add_test(t, check_journal_file_prune);
|
||||
suite_add_tcase(s, t);
|
||||
|
||||
t = tcase_create("print journal");
|
||||
tcase_add_unchecked_fixture(t, journal_entry_setup,
|
||||
journal_entry_teardown);
|
||||
tcase_add_test(t, check_journal_print);
|
||||
tcase_add_test(t, check_journal_filter_by_class);
|
||||
tcase_add_test(t, check_journal_filter_by_class_prefix);
|
||||
tcase_add_test(t, check_journal_filter_by_event_id);
|
||||
suite_add_tcase(s, t);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Suite *s;
|
||||
SRunner *sr;
|
||||
|
||||
s = config_suite();
|
||||
sr = srunner_create(s);
|
||||
|
||||
// Use the TAP driver for now, so that each
|
||||
// unit test will PASS/FAIL in the log output.
|
||||
srunner_set_log(sr, NULL);
|
||||
srunner_set_tap(sr, "-");
|
||||
|
||||
srunner_run_all(sr, CK_SILENT);
|
||||
// failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
// if you want the TAP driver to report a hard error based
|
||||
// on certain conditions (e.g. number of failed tests, etc.),
|
||||
// return non-zero here instead.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "telemetry.h"
|
||||
|
||||
static struct telem_ref *ref = NULL;
|
||||
static char *original_event_id = NULL;
|
||||
|
||||
void create_setup(void)
|
||||
{
|
||||
@@ -157,6 +158,87 @@ START_TEST(record_create_severity_overflow)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void event_id_setup(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (ref) {
|
||||
return;
|
||||
}
|
||||
|
||||
ret = tm_create_record(&ref, 1, "t/t/t", 2000);
|
||||
original_event_id = strdup(ref->record->headers[TM_EVENT_ID]);
|
||||
if (!original_event_id) {
|
||||
return;
|
||||
}
|
||||
ck_assert_msg(ret != -ECONNREFUSED,
|
||||
"Opt-out enabled. Opt in to run this test");
|
||||
}
|
||||
|
||||
START_TEST(record_set_event_id)
|
||||
{
|
||||
int ret;
|
||||
char *event_id = "aaaaaa00000033333344444466666622";
|
||||
char *result;
|
||||
if (asprintf(&result, "%s: %s\n", TM_EVENT_ID_STR, event_id) < 0) {
|
||||
return;
|
||||
}
|
||||
ck_assert_str_ne(ref->record->headers[TM_EVENT_ID], result);
|
||||
ret = tm_set_event_id(ref, event_id);
|
||||
ck_assert_int_eq(ret, 0);
|
||||
ck_assert_str_eq(ref->record->headers[TM_EVENT_ID], result);
|
||||
free(result);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(record_set_event_id_invalid_chars)
|
||||
{
|
||||
int ret;
|
||||
char *event_id = "aaaaaa000000333333444444666666ZZ";
|
||||
ret = tm_set_event_id(ref, event_id);
|
||||
ck_assert_int_eq(ret, -1);
|
||||
ck_assert_str_eq(ref->record->headers[TM_EVENT_ID], original_event_id);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(record_set_event_id_null)
|
||||
{
|
||||
int ret;
|
||||
char *event_id = NULL;
|
||||
ret = tm_set_event_id(ref, event_id);
|
||||
ck_assert_int_eq(ret, -1);
|
||||
ck_assert_str_eq(ref->record->headers[TM_EVENT_ID], original_event_id);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(record_set_event_id_short)
|
||||
{
|
||||
int ret;
|
||||
char *event_id = "aaaa";
|
||||
ret = tm_set_event_id(ref, event_id);
|
||||
ck_assert_int_eq(ret, -1);
|
||||
ck_assert_str_eq(ref->record->headers[TM_EVENT_ID], original_event_id);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(record_set_event_id_long)
|
||||
{
|
||||
int ret;
|
||||
char *event_id = "0000000000000000000000000000000000000000000";
|
||||
ret = tm_set_event_id(ref, event_id);
|
||||
ck_assert_int_eq(ret, -1);
|
||||
ck_assert_str_eq(ref->record->headers[TM_EVENT_ID], original_event_id);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void event_id_teardown(void)
|
||||
{
|
||||
if (ref) {
|
||||
free(ref);
|
||||
}
|
||||
free(original_event_id);
|
||||
}
|
||||
|
||||
Suite *lib_suite(void)
|
||||
{
|
||||
Suite *s = suite_create("libtelemetry");
|
||||
@@ -180,6 +262,15 @@ Suite *lib_suite(void)
|
||||
tcase_add_test(t, record_create_severity_overflow);
|
||||
suite_add_tcase(s, t);
|
||||
|
||||
t = tcase_create("event id");
|
||||
tcase_add_unchecked_fixture(t, event_id_setup, event_id_teardown);
|
||||
tcase_add_test(t, record_set_event_id);
|
||||
tcase_add_test(t, record_set_event_id_invalid_chars);
|
||||
tcase_add_test(t, record_set_event_id_null);
|
||||
tcase_add_test(t, record_set_event_id_short);
|
||||
tcase_add_test(t, record_set_event_id_long);
|
||||
suite_add_tcase(s, t);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
/*
|
||||
* This program is part of the Clear Linux Project
|
||||
*
|
||||
* Copyright 2017 Intel Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms and conditions 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 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.
|
||||
*/
|
||||
|
||||
#define OUT_MAX_LEN 100
|
||||
|
||||
#include <stdio.h>
|
||||
#include <check.h>
|
||||
#include "nica/b64enc.h"
|
||||
|
||||
START_TEST(check_nc_b64_no_overflow)
|
||||
{
|
||||
size_t n = 2;
|
||||
char out[OUT_MAX_LEN];
|
||||
const char *filename = TOPSRCDIR "/tests/nc_b64enc_test_files/foobar";
|
||||
|
||||
ck_assert_msg(!nc_b64enc_filename(filename, &out[0], n), "Should quit since buffer smaller than content");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_nc_b64_enc_n_file_empty)
|
||||
{
|
||||
size_t n = OUT_MAX_LEN;
|
||||
char out[OUT_MAX_LEN];
|
||||
char *result = "\0";
|
||||
const char *filename = TOPSRCDIR "/tests/nc_b64enc_test_files/empty";
|
||||
|
||||
ck_assert_msg(nc_b64enc_filename(filename, &out[0], n), "Error opening file");
|
||||
ck_assert_str_eq(out, result);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_nc_b64_enc_n_file_fo)
|
||||
{
|
||||
size_t n = OUT_MAX_LEN;
|
||||
char out[OUT_MAX_LEN];
|
||||
char *result = "Zm8=";
|
||||
const char *filename = TOPSRCDIR "/tests/nc_b64enc_test_files/fo";
|
||||
|
||||
ck_assert_msg(nc_b64enc_filename(filename, &out[0], n), "Error opening file");
|
||||
ck_assert_str_eq(out, result);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_nc_b64_enc_n_file_foob)
|
||||
{
|
||||
size_t n = OUT_MAX_LEN;
|
||||
char out[OUT_MAX_LEN];
|
||||
char *result = "Zm9vYg==";
|
||||
const char *filename = TOPSRCDIR "/tests/nc_b64enc_test_files/foob";
|
||||
|
||||
ck_assert_msg(nc_b64enc_filename(filename, &out[0], n), "Error opening file");
|
||||
ck_assert_str_eq(out, result);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_nc_b64_enc_n_file_foobar)
|
||||
{
|
||||
size_t n = OUT_MAX_LEN;
|
||||
char out[OUT_MAX_LEN];
|
||||
char *result = "Zm9vYmFyZm9vYmFy";
|
||||
const char *filename = TOPSRCDIR "/tests/nc_b64enc_test_files/foobar";
|
||||
|
||||
ck_assert_msg(nc_b64enc_filename(filename, &out[0], n), "Error opening file");
|
||||
ck_assert_str_eq(out, result);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_nc_b64_enc_n_file_long_text)
|
||||
{
|
||||
size_t out_len = 8000;
|
||||
char out[out_len];
|
||||
const char *expected_out = \
|
||||
"TG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIG5vbnVtbXkgdml0YWUsIGluIHZpdmFtdXMgc3Vz\n"
|
||||
"cGVuZGlzc2UgYWMuIFNlbXBlciBzZWQgcGhhcmV0cmEgc2NlbGVyaXNxdWUuIEVnZXQgZWxlaWZl\n"
|
||||
"bmQgYW1ldCB2ZWwgbnVuYyB2b2x1dHBhdCBjdXJzdXMsIGF1Y3RvciBwbGF0ZWEgcHJldGl1bSwg\n"
|
||||
"bWF0dGlzIHJpc3VzIGZhY2lsaXNpcyBmYXVjaWJ1cywgc3VzcGVuZGlzc2UgZGlhbSwgbGVjdHVz\n"
|
||||
"IG1ldHVzIG51bGxhLiBOdW5jIGp1c3RvIGZhY2lsaXNpIG5hbSBmZWxpcyB2ZWwgbGFvcmVldCwg\n"
|
||||
"bmliaCBsZW8gbWFzc2Egc3VzcGVuZGlzc2UgYWNjdW1zYW4gY29udmFsbGlzLCBzZWQgcXVpcyBw\n"
|
||||
"ZWxsZW50ZXNxdWUgZWdlc3RhcywgbG9yZW0gYW50ZSBtb3JiaSBtYXR0aXMgdml0YWUuIFByYWVz\n"
|
||||
"ZW50IGluIHJ1dHJ1bSBlZ2V0IGFjLCB2aXZhbXVzIHBlZGUgc3VzcGVuZGlzc2UgbGVjdHVzIG51\n"
|
||||
"bGxhbSwgZXQgcGVkZSBldSBvZGlvIHBlZGUsIGV0aWFtIGxlbyBlZ2VzdGFzIGluLCBub251bW15\n"
|
||||
"IHNlbXBlci4gQSBhY2N1bXNhbiBkdWksIHZlc3RpYnVsdW0gcmlkaWN1bHVzIGV0IGluLCBqdXN0\n"
|
||||
"byBldCBwbGFjZXJhdCBkdWlzIHV0IHZpdmFtdXMgbGliZXJvLiBWZXN0aWJ1bHVtIGVnZXQgdXQg\n"
|
||||
"bW9sbGlzLCBudW5jIGEgc29sbGljaXR1ZGluLCBmcmluZ2lsbGEgZXJvcyBwb3N1ZXJlIG1vbGxp\n"
|
||||
"cyBhYyBuYXRvcXVlIHBlZGUsIHJpc3VzIG51bGxhIHJ1dHJ1bSB0dXJwaXMgYSB2aXRhZSBpZC4g\n"
|
||||
"SW5jZXB0b3MgdGluY2lkdW50IHF1aWRlbSBhcmN1IHR1cnBpcyBudW5jIHNvbGxpY2l0dWRpbi4g\n"
|
||||
"UGhhc2VsbHVzIG1ldHVzIGVyYXQgcGxhY2VyYXQsIGluIGVyYXQgbG9yZW0gbWF1cmlzIG51bGxh\n"
|
||||
"LCBhdCBsaWJlcm8gZXJhdCBzdXNwZW5kaXNzZSBzYXBpZW4gbW9udGVzIHJob25jdXMsIG1hZ25h\n"
|
||||
"IHF1YW0uIEp1c3RvIHByYWVzZW50IGxhY3VzIG1hc3NhLCByZXByZWhlbmRlcml0IG51bmMsIHJp\n"
|
||||
"c3VzIGRpZ25pc3NpbSBmZWxpcyBub24sIGRpZ25pc3NpbSBvZGlvIHRlbGx1cyBhbGlxdWFtLCBl\n"
|
||||
"bmltIHNvZGFsZXMgdGVtcG9yIHF1aXNxdWUgc29kYWxlcyBtYWduaXMgcG9ydHRpdG9yLiBMaWd1\n"
|
||||
"bGEgc2VkIHJpc3VzLCBldSBlc3QgcXVpc3F1ZSwgY2xhc3Mgbm9uIGF1dGUgZXUsIHBsYXRlYSBz\n"
|
||||
"Y2VsZXJpc3F1ZSBpZCBpbnRlZ2VyIGRpZ25pc3NpbW9zIGludGVnZXIgc3VzY2lwaXQuClZlaGlj\n"
|
||||
"dWxhIGVpdXMgbmVjLCBjb252YWxsaXMgbWFlY2VuYXMgbGVjdHVzIHB1cnVzIHF1aXNxdWUgYWxp\n"
|
||||
"cXVhbSwgZXQgZXQsIGxhY2luaWEgZGlzIGRpZ25pc3NpbSBsb3JlbS4gVm9sdXB0YXRlbSB1dCwg\n"
|
||||
"dml2ZXJyYSBhZW5lYW4gcGhhc2VsbHVzIGZlbGlzLCBmZXJtZW50dW0gbGlndWxhIGVnZXQgdWxs\n"
|
||||
"YW1jb3JwZXIgYW1ldCwgbWF1cmlzIGxlbyBsdWN0dXMuIEV0IGV0aWFtIHNlbXBlciBwaGFyZXRy\n"
|
||||
"YSBuaWJoIG1pIG1hdXJpcy4gSGVuZHJlcml0IHNlZCBhbGlxdWFtLCBlZ2V0IGlkIHRlbGx1cyBt\n"
|
||||
"YWduYSwgc2VkIGxhb3JlZXQgdWx0cmljZXMgZW5pbSwgbW9sbGlzIHN1c3BlbmRpc3NlIGluLiBF\n"
|
||||
"dSBudWxsYW0gbG9yZW0gc2l0IGV0aWFtLCBvcmNpIGluIGxpYmVyby4gTnVuYyBpcHN1bSBtYXVy\n"
|
||||
"aXMgZXQgc2VtIGhhYy4gRGljdHVtIGZhdWNpYnVzIGRpcyB2aXRhZSBpbiB2b2x1dHBhdCBtb3Ji\n"
|
||||
"aSwgYSBkaWN0dW0sIHF1aXNxdWUgbWF1cmlzLCBhdWN0b3IgbmVjIHZlbCBwZWxsZW50ZXNxdWUg\n"
|
||||
"dWxsYW1jb3JwZXIgZXRpYW0uIEN1bSBsaWJlcm8gd2lzaSBhY2N1bXNhbiBhbGlxdWFtIGNvbnNl\n"
|
||||
"Y3RldHVlciB0ZWxsdXMsIHBoYXNlbGx1cyBjdXJhZSwgYXQgaWxsdW0gYW50ZSBwcmV0aXVtIG5p\n"
|
||||
"YmggbW9yYmkuIFNlZCBibGFuZGl0IHB1bHZpbmFyIHB1bHZpbmFyLiBEaWN0dW0gZXN0IG51bmMg\n"
|
||||
"ZWxlaWZlbmQsIHZlbGl0IHZlbGl0IHRlbXBvciBhY2N1bXNhbiBsb2JvcnRpcyBsYW9yZWV0IGNv\n"
|
||||
"bmd1ZS4gU2l0IGFtZXQsIHNlZCBuaWJoIHBvcnJvIG5lcXVlIGF1Y3RvciBoeW1lbmFlb3MgcG9z\n"
|
||||
"dWVyZSwgb2RpbyBudWxsYSBibGFuZGl0IGNvbmd1ZSBlbGl0LiBJZCBmYXVjaWJ1cyBldCB0ZW1w\n"
|
||||
"dXMgbWFsZXN1YWRhIHBsYXRlYS4=";
|
||||
const char *filename = TOPSRCDIR "/tests/nc_b64enc_test_files/long_text";
|
||||
|
||||
ck_assert_msg(nc_b64enc_filename(filename, &out[0], out_len), "Error opening file");
|
||||
ck_assert_str_eq(out, expected_out);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_nc_b64_enc_n_filehandler_foobar)
|
||||
{
|
||||
size_t n = OUT_MAX_LEN;
|
||||
char out[OUT_MAX_LEN];
|
||||
char *result = "Zm9vYmFyZm9vYmFy";
|
||||
const char *filename = TOPSRCDIR "/tests/nc_b64enc_test_files/foobar";
|
||||
FILE *fh = NULL;
|
||||
|
||||
fh = fopen(filename, "rb");
|
||||
|
||||
if (fh == NULL) {
|
||||
ck_abort_msg("Unable to open foobar file");
|
||||
}
|
||||
|
||||
ck_assert_msg(nc_b64enc_file(fh, &out[0], n), "Result does not match");
|
||||
ck_assert_str_eq(out, result);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
Suite *config_suite(void)
|
||||
{
|
||||
// A suite is comprised of test cases, defined below
|
||||
Suite *s = suite_create("nc_b64enc");
|
||||
|
||||
// Individual unit tests are added to "test cases"
|
||||
TCase *t = tcase_create("nc_b64enc");
|
||||
tcase_add_test(t, check_nc_b64_no_overflow);
|
||||
tcase_add_test(t, check_nc_b64_enc_n_file_empty);
|
||||
tcase_add_test(t, check_nc_b64_enc_n_file_fo);
|
||||
tcase_add_test(t, check_nc_b64_enc_n_file_foob);
|
||||
tcase_add_test(t, check_nc_b64_enc_n_file_foobar);
|
||||
tcase_add_test(t, check_nc_b64_enc_n_file_long_text);
|
||||
tcase_add_test(t, check_nc_b64_enc_n_filehandler_foobar);
|
||||
|
||||
suite_add_tcase(s, t);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Suite *s;
|
||||
SRunner *sr;
|
||||
|
||||
s = config_suite();
|
||||
sr = srunner_create(s);
|
||||
|
||||
// Use the TAP driver for now, so that each
|
||||
// unit test will PASS/FAIL in the log output.
|
||||
srunner_set_log(sr, NULL);
|
||||
srunner_set_tap(sr, "-");
|
||||
|
||||
srunner_run_all(sr, CK_SILENT);
|
||||
// failed = srunner_ntests_failed(sr);
|
||||
srunner_free(sr);
|
||||
|
||||
// if you want the TAP driver to report a hard error based
|
||||
// on certain conditions (e.g. number of failed tests, etc.),
|
||||
// return non-zero here instead.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
|
||||
|
||||
+38
-1
@@ -14,6 +14,8 @@ check_PROGRAMS = \
|
||||
%D%/check_config \
|
||||
%D%/check_daemon \
|
||||
%D%/check_probes \
|
||||
%D%/check_ncb64 \
|
||||
%D%/check_journal \
|
||||
%D%/check_libtelemetry
|
||||
|
||||
dist_check_SCRIPTS = \
|
||||
@@ -33,7 +35,9 @@ dist_check_SCRIPTS = \
|
||||
%C%_check_daemon_SOURCES = \
|
||||
%D%/check_daemon.c \
|
||||
src/telemdaemon.c \
|
||||
src/telemdaemon.h
|
||||
src/telemdaemon.h \
|
||||
src/journal/journal.c \
|
||||
src/journal/journal.h
|
||||
|
||||
%C%_check_daemon_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
@@ -106,6 +110,39 @@ if HAVE_SYSTEMD_JOURNAL
|
||||
endif
|
||||
endif
|
||||
|
||||
%C%_check_ncb64_SOURCES = \
|
||||
%D%/check_ncb64.c \
|
||||
src/nica/b64enc.h \
|
||||
src/nica/b64enc.c
|
||||
|
||||
%C%_check_ncb64_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
@CHECK_CFLAGS@
|
||||
|
||||
%C%_check_ncb64_LDADD = \
|
||||
@CHECK_LIBS@
|
||||
|
||||
EXTRA_DIST += \
|
||||
%D%/nc_b64enc_test_files/empty \
|
||||
%D%/nc_b64enc_test_files/fo \
|
||||
%D%/nc_b64enc_test_files/foob \
|
||||
%D%/nc_b64enc_test_files/foobar \
|
||||
%D%/nc_b64enc_test_files/long_text
|
||||
|
||||
%C%_check_journal_SOURCES = \
|
||||
%D%/check_journal.c \
|
||||
src/journal/journal.h \
|
||||
src/journal/journal.c \
|
||||
src/util.h \
|
||||
src/util.c
|
||||
|
||||
%C%_check_journal_CFLAGS = \
|
||||
$(AM_CFLAGS) \
|
||||
@CHECK_CFLAGS@
|
||||
|
||||
%C%_check_journal_LDADD = \
|
||||
@CHECK_LIBS@
|
||||
|
||||
%C%_check_libtelemetry_SOURCES = \
|
||||
%D%/check_libtelemetry.c \
|
||||
src/telemetry.c
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
fo
|
||||
@@ -0,0 +1 @@
|
||||
foob
|
||||
@@ -0,0 +1 @@
|
||||
foobarfoobar
|
||||
@@ -0,0 +1,2 @@
|
||||
Lorem ipsum dolor sit amet, nonummy vitae, in vivamus suspendisse ac. Semper sed pharetra scelerisque. Eget eleifend amet vel nunc volutpat cursus, auctor platea pretium, mattis risus facilisis faucibus, suspendisse diam, lectus metus nulla. Nunc justo facilisi nam felis vel laoreet, nibh leo massa suspendisse accumsan convallis, sed quis pellentesque egestas, lorem ante morbi mattis vitae. Praesent in rutrum eget ac, vivamus pede suspendisse lectus nullam, et pede eu odio pede, etiam leo egestas in, nonummy semper. A accumsan dui, vestibulum ridiculus et in, justo et placerat duis ut vivamus libero. Vestibulum eget ut mollis, nunc a sollicitudin, fringilla eros posuere mollis ac natoque pede, risus nulla rutrum turpis a vitae id. Inceptos tincidunt quidem arcu turpis nunc sollicitudin. Phasellus metus erat placerat, in erat lorem mauris nulla, at libero erat suspendisse sapien montes rhoncus, magna quam. Justo praesent lacus massa, reprehenderit nunc, risus dignissim felis non, dignissim odio tellus aliquam, enim sodales tempor quisque sodales magnis porttitor. Ligula sed risus, eu est quisque, class non aute eu, platea scelerisque id integer dignissimos integer suscipit.
|
||||
Vehicula eius nec, convallis maecenas lectus purus quisque aliquam, et et, lacinia dis dignissim lorem. Voluptatem ut, viverra aenean phasellus felis, fermentum ligula eget ullamcorper amet, mauris leo luctus. Et etiam semper pharetra nibh mi mauris. Hendrerit sed aliquam, eget id tellus magna, sed laoreet ultrices enim, mollis suspendisse in. Eu nullam lorem sit etiam, orci in libero. Nunc ipsum mauris et sem hac. Dictum faucibus dis vitae in volutpat morbi, a dictum, quisque mauris, auctor nec vel pellentesque ullamcorper etiam. Cum libero wisi accumsan aliquam consectetuer tellus, phasellus curae, at illum ante pretium nibh morbi. Sed blandit pulvinar pulvinar. Dictum est nunc eleifend, velit velit tempor accumsan lobortis laoreet congue. Sit amet, sed nibh porro neque auctor hymenaeos posuere, odio nulla blandit congue elit. Id faucibus et tempus malesuada platea.
|
||||
Reference in New Issue
Block a user