mirror of
https://github.com/clearlinux/telemetrics-client.git
synced 2026-09-01 11:15:51 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8ca299314c | ||
|
|
53d4c229a7 | ||
|
|
7a3082eb59 | ||
|
|
071ad2c883 | ||
|
|
72ea0d9360 | ||
|
|
49823eae83 | ||
|
|
a12c1d8761 | ||
|
|
eb1e670b5f | ||
|
|
5cbd31cbf2 | ||
|
|
4119bdea33 | ||
|
|
2395f6bf3e | ||
|
|
bc7e2610ee | ||
|
|
a4774bde2e | ||
|
|
63574e7406 | ||
|
|
ce35876b55 | ||
|
|
055e55b2f3 | ||
|
|
84b4266bc2 | ||
|
|
e7d9d7b0ba | ||
|
|
b0effc8850 | ||
|
|
e9ce8bc1ae | ||
|
|
ea1480fb04 | ||
|
|
a6e81aa3bb | ||
|
|
fffe9755ad | ||
|
|
b465d35b24 | ||
|
|
e2aeda86eb | ||
|
|
6b4089075f | ||
|
|
83bb3df20a | ||
|
|
e855a19c88 | ||
|
|
7173e1fede | ||
|
|
a4bc8b55dd | ||
|
|
d81ac1e8f3 | ||
|
|
b0d448e9e7 | ||
|
|
88ee43f528 | ||
|
|
49a1d41a3a | ||
|
|
0e20d62c9e | ||
|
|
d314c1a88b | ||
|
|
b9ad4c2f14 | ||
|
|
9fd3c280ba | ||
|
|
75255fff50 | ||
|
|
b2adc08d4f | ||
|
|
e6357bb051 | ||
|
|
15b5df2f47 | ||
|
|
f516d85e59 | ||
|
|
ce2ad0c2b0 | ||
|
|
afb7572adf | ||
|
|
3337c45b08 | ||
|
|
672e741e5d | ||
|
|
e19e72a5b3 | ||
|
|
9a25115d8e | ||
|
|
11c5808fd9 | ||
|
|
9f67a1ca8a | ||
|
|
781d9382d0 | ||
|
|
2a29191c5f | ||
|
|
c264cd044c | ||
|
|
ad4dde288b | ||
|
|
48527a343b | ||
|
|
d13073ff25 | ||
|
|
43c506382a | ||
|
|
aca23d1c54 | ||
|
|
2639e4d042 | ||
|
|
cc70c3ffba | ||
|
|
ba62496248 | ||
|
|
d873c4e067 | ||
|
|
335ed440bc | ||
|
|
297e59fe5b | ||
|
|
4a2cfd99ad |
@@ -0,0 +1,29 @@
|
||||
name: C/C++ CI
|
||||
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: install dependencies
|
||||
run: sudo apt-get install libcurl4-gnutls-dev valgrind libelf-dev libdw-dev
|
||||
- name: install check
|
||||
run: wget https://github.com/libcheck/check/releases/download/0.12.0/check-0.12.0.tar.gz &&
|
||||
tar xf check-0.12.0.tar.gz &&
|
||||
pushd check-0.12.0 &&
|
||||
./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu &&
|
||||
make -j8 && sudo make install && popd
|
||||
- name: autogen
|
||||
run: sh autogen.sh
|
||||
- name: configure
|
||||
run: ./configure
|
||||
- name: make
|
||||
run: make -j8
|
||||
- name: check
|
||||
run: make check
|
||||
- name: make distcheck
|
||||
run: make distcheck
|
||||
@@ -39,10 +39,8 @@ autoscan.log
|
||||
configure.scan
|
||||
tprobe
|
||||
hprobe
|
||||
bertprobe
|
||||
crashprobe
|
||||
journalprobe
|
||||
pythonprobe
|
||||
telem-record-gen
|
||||
klogscanner
|
||||
pstoreclean
|
||||
@@ -58,7 +56,6 @@ tests/check_config
|
||||
tests/check_daemon
|
||||
tests/check_journal
|
||||
tests/check_libtelemetry
|
||||
tests/check_ncb64
|
||||
tests/check_postd
|
||||
tests/check_probd
|
||||
tests/check_probes
|
||||
|
||||
@@ -3,3 +3,6 @@ Patrick McCarty <patrick.mccarty@intel.com>
|
||||
Rob Nesius <robert.a.nesius@intel.com>
|
||||
Gabrielle N. Beyer <gabrielle.n.beyer@intel.com>
|
||||
Pam Leonard <pam.leonard@intel.com>
|
||||
Alex V. Jaramillo <alex.v.jaramillo@intel.com>
|
||||
California Sullivan <california.l.sullivan@intel.com>
|
||||
Juro Bystricky <juro.bystricky@intel.com>
|
||||
|
||||
@@ -15,7 +15,6 @@ DISTCHECK_CONFIGURE_FLAGS = \
|
||||
include $(top_srcdir)/build-aux/make/cflags.make
|
||||
include $(top_srcdir)/build-aux/make/ldflags.make
|
||||
include $(top_srcdir)/docs/local.mk
|
||||
include $(top_srcdir)/scripts/local.mk
|
||||
include $(top_srcdir)/src/local.mk
|
||||
include $(top_srcdir)/src/data/local.mk
|
||||
include $(top_srcdir)/src/nica/local.mk
|
||||
|
||||
@@ -67,38 +67,47 @@ Descriptions of config options are listed below in the Usage section.
|
||||
|
||||
Starting the client
|
||||
---------------------
|
||||
To use the telemetrics client a one time explicit ```opt-in``` is required (this is
|
||||
also true when the contents of the directory ```/etc/telemetrics/``` are removed).
|
||||
To opt-in to telemetrics-client use the command:
|
||||
|
||||
```{r, engine='bash', count_lines}
|
||||
telemctl opt-in
|
||||
```
|
||||
|
||||
**Note** this is a change from previous versions, before 2.3.0 installation of
|
||||
telemetrics client was enough to enable the client and if needed the client could
|
||||
be disabled with ```telemctl opt-out```. This command in previous versions created
|
||||
```/etc/telemetrics/opt-out``` file (after telemetrics-client version 2.3.0 this
|
||||
file can be safely removed).
|
||||
|
||||
If the client was compiled with systemd support the respective activation units
|
||||
should be already in place (after a ```make install``` invocation). In this case
|
||||
the client wil start automatically when data is made available to it. i.e. when
|
||||
executing an ```/usr/bin/hprobe``` command.
|
||||
|
||||
Method 1 (recommended):
|
||||
executing an ```/usr/bin/hprobe``` command. Otherwise use the following command:
|
||||
|
||||
```{r, engine='bash', count_lines}
|
||||
telemctl start
|
||||
```
|
||||
|
||||
Note: the above invocation technically readies the service for both socket and
|
||||
path activation, so you may not see an "active" status.
|
||||
|
||||
Method 2:
|
||||
path activation, so you may not see an "active" status. To check the status of
|
||||
telemetrics-client use:
|
||||
|
||||
```{r, engine='bash', count_lines}
|
||||
systemctl start telemprobd.service
|
||||
systemctl start telempostd.service
|
||||
telemctl is-active
|
||||
telemprobd : active
|
||||
telempostd : active
|
||||
```
|
||||
|
||||
Method 3:
|
||||
|
||||
```{r, engine='bash', count_lines}
|
||||
telemprobd &
|
||||
telempostd &
|
||||
```
|
||||
Starting individual service units ```telempostd.service``` or ```telemeprobd.service```
|
||||
is discouraged.
|
||||
|
||||
Configure the client to autostart at boot
|
||||
---------------------
|
||||
|
||||
As longs as the first time ```opt-in``` was performed, the following methods are valid:
|
||||
|
||||
|
||||
Method 1 (recommended):
|
||||
|
||||
Enable the socket-activated service and path unit:
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
Build
|
||||
=====
|
||||
- make sure our AM_CFLAGS do not break older compilers, e.g. compilers
|
||||
that do not support -fstack-protector-strong
|
||||
|
||||
Probes
|
||||
======
|
||||
- add pstore probe (Archana)
|
||||
- journal probe: detect kernel oopses (Patrick)
|
||||
- crash probe: add function/register value info to crash payloads (Patrick)
|
||||
- crash probe: if some symbols are missing from backtraces, attempt the
|
||||
debuginfo lookup again after a certain timeout (Patrick)
|
||||
- crash probe: for non-debug builds, ensure that we are invoked by the kernel,
|
||||
and write tests to verify that attempts to run the crash probe for non-debug
|
||||
builds fail. (Patrick)
|
||||
|
||||
Library
|
||||
=======
|
||||
- add API for structured payloads
|
||||
|
||||
Other
|
||||
=====
|
||||
- set fixed size for system-wide core file ulimit, and afterward notify QA team
|
||||
to update the BAT test that checks for the ulimit value.
|
||||
@@ -12,7 +12,10 @@ AM_CFLAGS = \
|
||||
-Wunreachable-code \
|
||||
-funsigned-char \
|
||||
-fPIE \
|
||||
-fPIC
|
||||
-fPIC \
|
||||
-fno-strict-overflow \
|
||||
-fno-delete-null-pointer-checks \
|
||||
-fwrapv
|
||||
|
||||
AM_CPPFLAGS = \
|
||||
-D_FORTIFY_SOURCE=2 \
|
||||
@@ -25,6 +28,7 @@ AM_CPPFLAGS = \
|
||||
-DDATADIR=\"$(datadir)\" \
|
||||
-DLOCALSTATEDIR=\"$(localstatedir)\" \
|
||||
-DPSTOREDIR=\"$(localstatedir)/cache/telemetry/pstore\" \
|
||||
-DTESTOOPSDIR=\"$(top_srcdir)/tests/oops_test_files\"
|
||||
-DTESTOOPSDIR=\"$(top_srcdir)/tests/oops_test_files\" \
|
||||
-DBACKEND_ADDR=\"$(BACKEND_ADDR)\"
|
||||
|
||||
# vim: filetype=automake tabstop=8 shiftwidth=8 noexpandtab
|
||||
|
||||
+6
-1
@@ -2,7 +2,7 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.69])
|
||||
AC_INIT([telemetrics-client], [2.1.1], [https://clearlinux.org/])
|
||||
AC_INIT([telemetrics-client], [2.3.2], [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])
|
||||
@@ -119,6 +119,11 @@ AC_ARG_WITH([loglevel], AS_HELP_STRING([--with-loglevel=NUM],
|
||||
[loglevel=5])
|
||||
AC_DEFINE_UNQUOTED([MAX_LOG_LEVEL], [${loglevel}], [Maximum log level for binaries])
|
||||
|
||||
AC_ARG_WITH([backendserveraddr], AS_HELP_STRING([--with-backendserveraddr=URI],
|
||||
[uri to telemetrics backend server @<:@default=https://clr.telemetry.intel.com/v2/collector@:>@]), [backendaddr=${withval}])
|
||||
test -z "${backendaddr}" && backendaddr=https://clr.telemetry.intel.com/v2/collector
|
||||
AC_SUBST(BACKEND_ADDR, [${backendaddr}])
|
||||
|
||||
AC_ARG_ENABLE([logtype], AS_HELP_STRING([--enable-logtype],
|
||||
[Vector for logging: stderr (default), syslog, systemd]),
|
||||
[case ${enableval} in
|
||||
|
||||
@@ -89,7 +89,7 @@ Event id to use in the record. If not provided a randomly generated id will be a
|
||||
.SH SEE ALSO
|
||||
.INDENT 0.0
|
||||
.IP \(bu 2
|
||||
\fBtelemd\fP(1)
|
||||
\fBtelemprobd\fP(1)
|
||||
.IP \(bu 2
|
||||
\fI\%https://github.com/clearlinux/telemetrics\-client\fP
|
||||
.IP \(bu 2
|
||||
|
||||
@@ -76,6 +76,6 @@ RETURN VALUES
|
||||
SEE ALSO
|
||||
========
|
||||
|
||||
* ``telemd``\(1)
|
||||
* ``telemprobd``\(1)
|
||||
* https://github.com/clearlinux/telemetrics-client
|
||||
* https://clearlinux.org/documentation/
|
||||
|
||||
+7
-6
@@ -34,7 +34,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
.sp
|
||||
\fBtelemctl\fP
|
||||
.sp
|
||||
\fB/etc/telemetrics/opt\-out\fP
|
||||
\fB/etc/telemetrics/opt\-in\fP
|
||||
.SH DESCRIPTION
|
||||
.sp
|
||||
Control actions for telemetry services. The command can be used to start,
|
||||
@@ -48,12 +48,13 @@ restart, or stop \fBtelemprobd\fP(1) and \fBtelempostd\fP(1), or to opt\-in or o
|
||||
Starts, stops or restarts all running telemetry services.
|
||||
.IP \(bu 2
|
||||
\fBopt\-in\fP:
|
||||
Opts in to telemetry, and starts telemetry services. The opt\-out file
|
||||
\fB/etc/telemetrics/opt\-out\fP is removed.
|
||||
Opts in to telemetry and the opt\-in file \fB/etc/telemetrics/opt\-in\fP
|
||||
is created. Note: this is a one time required operation before
|
||||
telemetry can be used the first time.
|
||||
.IP \(bu 2
|
||||
\fBopt\-out\fP:
|
||||
Opts out of telemetry, and stops telemetry services. The opt\-out file
|
||||
\fB/etc/telemetrics/opt\-out\fP is created.
|
||||
Opts out of telemetry, and stops telemetry services. The opt\-in file
|
||||
\fB/etc/telemetrics/opt\-in\fP is deleted.
|
||||
.IP \(bu 2
|
||||
\fBis\-active\fP:
|
||||
Checks if telemetry client daemons are active (telemprobd and telempostd).
|
||||
@@ -66,7 +67,7 @@ Checks if telemetry client daemons are active (telemprobd and telempostd).
|
||||
.SH SEE ALSO
|
||||
.INDENT 0.0
|
||||
.IP \(bu 2
|
||||
\fBtelemd\fP(1)
|
||||
\fBtelemprobd\fP(1)
|
||||
.IP \(bu 2
|
||||
\fI\%https://github.com/clearlinux/telemetrics\-client\fP
|
||||
.IP \(bu 2
|
||||
|
||||
@@ -15,7 +15,7 @@ SYNOPSIS
|
||||
|
||||
``telemctl``
|
||||
|
||||
``/etc/telemetrics/opt-out``
|
||||
``/etc/telemetrics/opt-in``
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
@@ -32,12 +32,13 @@ OPTIONS
|
||||
Starts, stops or restarts all running telemetry services.
|
||||
|
||||
* ``opt-in``:
|
||||
Opts in to telemetry, and starts telemetry services. The opt-out file
|
||||
``/etc/telemetrics/opt-out`` is removed.
|
||||
Opts in to telemetry and the opt-in file ``/etc/telemetrics/opt-in``
|
||||
is created. Note: this is a one time required operation before
|
||||
telemetry can be used the first time.
|
||||
|
||||
* ``opt-out``:
|
||||
Opts out of telemetry, and stops telemetry services. The opt-out file
|
||||
``/etc/telemetrics/opt-out`` is created.
|
||||
Opts out of telemetry, and stops telemetry services. The opt-in file
|
||||
``/etc/telemetrics/opt-in`` is deleted.
|
||||
|
||||
* ``is-active``:
|
||||
Checks if telemetry client daemons are active (telemprobd and telempostd).
|
||||
@@ -52,6 +53,6 @@ RETURN VALUES
|
||||
SEE ALSO
|
||||
========
|
||||
|
||||
* ``telemd``\(1)
|
||||
* ``telemprobd``\(1)
|
||||
* https://github.com/clearlinux/telemetrics-client
|
||||
* https://clearlinux.org/documentation/
|
||||
|
||||
@@ -45,6 +45,8 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
\fBvoid tm_free_record(struct telem_ref *t_ref)\fP
|
||||
.sp
|
||||
\fBint tm_set_config_file(const char *c_file)\fP
|
||||
.sp
|
||||
\fBint tm_is_opted_in(void)\fP
|
||||
.SH DESCRIPTION
|
||||
.sp
|
||||
The functions in the telemetry library facilitate the delivery of
|
||||
@@ -60,15 +62,19 @@ The function \fBtm_set_payload()\fP attaches the provided telemetry record
|
||||
data to the telemetry record. The current maximum payload size is 8192b.
|
||||
.sp
|
||||
The function \fBtm_send_record()\fP delivers the record to the local
|
||||
\fBtelemd\fP(1) service.
|
||||
\fBtelemprobd\fP(1) service.
|
||||
.sp
|
||||
The function \fBtm_set_config_file()\fP can be used to provide an alternate
|
||||
configuration path to the telemetry library.
|
||||
.sp
|
||||
\fBtm_is_opted_in\fP is a utility provided to check if the one time opt\-in
|
||||
has been performed.
|
||||
.SH RETURN VALUES
|
||||
.sp
|
||||
All these functions return \fB0\fP on success, or a non\-zero return value
|
||||
if an error occurred. The function \fBtm_free_record()\fP does not return
|
||||
any value.
|
||||
any value. \fBtm_is_opted_in\fP returns \fB1\fP when telemetry is opted\-in
|
||||
otherwise \fB0\fP\&.
|
||||
.SH SEE ALSO
|
||||
.INDENT 0.0
|
||||
.IP \(bu 2
|
||||
|
||||
@@ -27,6 +27,8 @@ SYNOPSIS
|
||||
|
||||
``int tm_set_config_file(const char *c_file)``
|
||||
|
||||
``int tm_is_opted_in(void)``
|
||||
|
||||
|
||||
DESCRIPTION
|
||||
===========
|
||||
@@ -44,18 +46,21 @@ The function ``tm_set_payload()`` attaches the provided telemetry record
|
||||
data to the telemetry record. The current maximum payload size is 8192b.
|
||||
|
||||
The function ``tm_send_record()`` delivers the record to the local
|
||||
``telemd``\(1) service.
|
||||
``telemprobd``\(1) service.
|
||||
|
||||
The function ``tm_set_config_file()`` can be used to provide an alternate
|
||||
configuration path to the telemetry library.
|
||||
|
||||
``tm_is_opted_in`` is a utility provided to check if the one time opt-in
|
||||
has been performed.
|
||||
|
||||
RETURN VALUES
|
||||
=============
|
||||
|
||||
All these functions return ``0`` on success, or a non-zero return value
|
||||
if an error occurred. The function ``tm_free_record()`` does not return
|
||||
any value.
|
||||
any value. ``tm_is_opted_in`` returns ``1`` when telemetry is opted-in
|
||||
otherwise ``0``.
|
||||
|
||||
|
||||
SEE ALSO
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
dist_bin_SCRIPTS = %D%/telemctl
|
||||
|
||||
# vim: filetype=automake tabstop=8 shiftwidth=8 noexpandtab
|
||||
@@ -1,150 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
declare -a SPECIAL_UNITS=(
|
||||
hprobe.timer
|
||||
telemprobd.socket
|
||||
telempostd.path
|
||||
klogscanner.service
|
||||
journal-probe-tail.service
|
||||
python-probe.path
|
||||
)
|
||||
|
||||
declare -a SERVICES=(
|
||||
hprobe.service
|
||||
pstore-probe.service
|
||||
telemprobd.service
|
||||
telempostd.service
|
||||
journal-probe.service
|
||||
)
|
||||
|
||||
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
|
||||
exit 0
|
||||
}
|
||||
|
||||
exit_err() {
|
||||
echo "$1" > /dev/stderr
|
||||
exit 1
|
||||
}
|
||||
|
||||
notice() {
|
||||
echo "$1" > /dev/stderr
|
||||
}
|
||||
|
||||
for_each_service() {
|
||||
local action=$1 && shift
|
||||
local -a array=($*)
|
||||
for service in "${array[@]}"; do
|
||||
systemctl $action $service
|
||||
[ $? -ne 0 ] && notice "Failed to $action ${service}. Continuing..."
|
||||
done
|
||||
}
|
||||
|
||||
telem_stop() {
|
||||
# the special units must be stopped first so that activation no longer happens
|
||||
for_each_service "stop" ${SPECIAL_UNITS[@]}
|
||||
for_each_service "stop" ${SERVICES[@]}
|
||||
}
|
||||
|
||||
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
|
||||
echo "telemprobd :" $(systemctl is-active telemprobd.socket)
|
||||
echo "telempostd :" $(systemctl is-active telempostd.path)
|
||||
}
|
||||
|
||||
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() {
|
||||
[ ! -f $OPT_OUT_FILE ] && exit_ok "Already opted in. Nothing to do."
|
||||
rm -f $OPT_OUT_FILE || exit_err "Failed to remove ${OPT_OUT_FILE}."
|
||||
telem_start
|
||||
}
|
||||
|
||||
telem_restart() {
|
||||
telem_stop
|
||||
telem_start
|
||||
}
|
||||
|
||||
telem_journal_cli() {
|
||||
telem_journal "$@"
|
||||
}
|
||||
|
||||
usage() {
|
||||
format=' %-10s %s\n'
|
||||
printf "\n"
|
||||
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 telemprobd and telempostd are 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 telemtry journal contents. Use -h argument with"
|
||||
printf "$format" "" "command for more options"
|
||||
printf "\n"
|
||||
exit 2
|
||||
}
|
||||
|
||||
if [ "$1" != "journal" ] && [ $# -ne 1 ]; then
|
||||
usage
|
||||
fi
|
||||
|
||||
if [ $EUID -ne 0 ]; then
|
||||
exit_err "Must be root to run this command. Exiting..."
|
||||
fi
|
||||
|
||||
SUBCOMMAND=$1
|
||||
|
||||
case $SUBCOMMAND in
|
||||
opt-out)
|
||||
telem_opt_out ;;
|
||||
opt-in)
|
||||
telem_opt_in ;;
|
||||
stop)
|
||||
telem_stop ;;
|
||||
start)
|
||||
telem_start ;;
|
||||
restart)
|
||||
telem_restart ;;
|
||||
is-active)
|
||||
telem_is_active ;;
|
||||
journal)
|
||||
telem_journal_cli "$@" ;;
|
||||
*)
|
||||
notice "Unknown command passed to $SCRIPT"
|
||||
usage ;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
|
||||
# vi: ts=8 sw=2 sts=2 et tw=80
|
||||
+7
-1
@@ -75,7 +75,7 @@ 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"
|
||||
|
||||
#define TM_OPT_OUT_FILE "/etc/telemetrics/opt-out"
|
||||
#define TM_OPT_IN_FILE "/etc/telemetrics/opt-in"
|
||||
|
||||
/* Currently max supported payload size is 8kb */
|
||||
#define MAX_PAYLOAD_LENGTH 8192
|
||||
@@ -102,6 +102,11 @@ static const uint32_t RECORD_FORMAT_VERSION = 4;
|
||||
/* Maximum records that can be processed in a single spool run loop*/
|
||||
#define TM_SPOOL_MAX_PROCESS_RECORDS 60
|
||||
|
||||
/* Definitions for config file override */
|
||||
#define CFG_PREFIX "CFG:"
|
||||
#define CFG_PREFIX_LENGTH 4
|
||||
#define CFG_PREFIX_32BIT 0x3a474643
|
||||
|
||||
/* Very simple structure. Array of header strings and a payload. Calling
|
||||
* program is reponsible for passing in the payload as a simple string.
|
||||
*/
|
||||
@@ -114,4 +119,5 @@ struct telem_record {
|
||||
|
||||
const char *get_header_name(int ind);
|
||||
|
||||
|
||||
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
|
||||
|
||||
+110
-58
@@ -28,6 +28,7 @@
|
||||
#include "configuration.h"
|
||||
#include "util.h"
|
||||
#include "common.h"
|
||||
#include "log.h"
|
||||
|
||||
#include "nica/inifile.h"
|
||||
|
||||
@@ -38,17 +39,46 @@ static NcHashmap *keyfile = NULL;
|
||||
static bool cmd_line_cfg = false;
|
||||
|
||||
/* Conf strings, integers, and booleans expected in the conf file */
|
||||
const char *config_key_str[] = { NULL, "server", "socket_path", "spool_dir",
|
||||
"rate_limit_strategy", "cainfo",
|
||||
"tidheader", NULL };
|
||||
static const char *config_key_str[] = { "server",
|
||||
"socket_path",
|
||||
"spool_dir",
|
||||
"rate_limit_strategy",
|
||||
"cainfo",
|
||||
"tidheader"};
|
||||
|
||||
const char *config_key_int[] = { NULL, "record_expiry", "spool_max_size",
|
||||
"spool_process_time", "record_window_length",
|
||||
"byte_window_length", "record_burst_limit",
|
||||
"byte_burst_limit", NULL };
|
||||
static const char *config_key_int[] = { "record_expiry",
|
||||
"spool_max_size",
|
||||
"spool_process_time",
|
||||
"record_window_length",
|
||||
"byte_window_length",
|
||||
"record_burst_limit",
|
||||
"byte_burst_limit" };
|
||||
|
||||
static const char *config_key_bool[] = { "rate_limit_enabled",
|
||||
"daemon_recycling_enabled",
|
||||
"record_retention_enabled",
|
||||
"record_server_delivery_enabled" };
|
||||
|
||||
static const char *config_str_default[] = { DEFAULT_SERVER_ADDR,
|
||||
DEFAULT_SOCKET_PATH,
|
||||
DEFAULT_SPOOL_DIR,
|
||||
DEFAULT_RATE_LIMIT_STRATEGY,
|
||||
DEFAULT_CAINFO,
|
||||
DEFAULT_TIDHEADER };
|
||||
|
||||
static const bool config_bool_default[] = { DEFAULT_RATE_LIMIT_ENABLED,
|
||||
DEFAULT_DAEMON_RECYCLING_ENABLED,
|
||||
DEFAULT_RECORD_RETENTION_ENABLED,
|
||||
DEFAULT_RECORD_SERVER_DELIVERY_ENABLED };
|
||||
|
||||
static const int config_int_default[] = { DEFAULT_RECORD_EXPIRY,
|
||||
DEFAULT_SPOOL_MAX_SIZE,
|
||||
DEFAULT_SPOOL_PROCESS_TIME,
|
||||
DEFAULT_RECORD_WINDOW_LENGTH,
|
||||
DEFAULT_BYTE_WINDOW_LENGTH,
|
||||
DEFAULT_RECORD_BURST_LIMIT,
|
||||
DEFAULT_BYTE_BURST_LIMIT };
|
||||
|
||||
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 };
|
||||
|
||||
@@ -73,6 +103,19 @@ static int validate_config_file(const char *f)
|
||||
|
||||
}
|
||||
|
||||
const char *get_config_file(void)
|
||||
{
|
||||
return config_file;
|
||||
}
|
||||
|
||||
const char *get_cmd_line_config_file(void)
|
||||
{
|
||||
if (cmd_line_cfg == true) {
|
||||
return config_file;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int set_config_file(const char *filename)
|
||||
{
|
||||
int ret;
|
||||
@@ -90,6 +133,25 @@ int set_config_file(const char *filename)
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool set_default_config_values(struct configuration *config)
|
||||
{
|
||||
for (int i = 0; i < CONF_STR_MAX; i++) {
|
||||
config->strValues[i] = strdup(config_str_default[i]);
|
||||
if (config->strValues[i] == NULL) {
|
||||
telem_log(LOG_ERR, "Could not set config item %s: %s\n",
|
||||
config_key_str[i], strerror(errno));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < CONF_INT_MAX; i++) {
|
||||
config->intValues[i] = config_int_default[i];
|
||||
}
|
||||
for (int i = 0; i < CONF_BOOL_MAX; i++) {
|
||||
config->boolValues[i] = config_bool_default[i];
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool read_config_from_file(char *config_file, struct configuration *config)
|
||||
{
|
||||
if (keyfile != NULL) {
|
||||
@@ -98,73 +160,64 @@ 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\n");
|
||||
#endif
|
||||
telem_log(LOG_ERR, "Failed to read config file\n");
|
||||
return false;
|
||||
} else {
|
||||
for (int i = CONF_STR_MIN + 1; i < CONF_STR_MAX; i++) {
|
||||
for (int i = 0; i < CONF_STR_MAX; i++) {
|
||||
char *ptr;
|
||||
ptr = nc_hashmap_get(nc_hashmap_get(keyfile, "settings"), config_key_str[i]);
|
||||
if (ptr) {
|
||||
config->strValues[i] = strdup(ptr);
|
||||
if (config->strValues[i] == NULL) {
|
||||
telem_log(LOG_ERR, "Could not set config item %s: %s\n",
|
||||
config_key_str[i], strerror(errno));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "ERR: missing key with string value: %s\n", config_key_str[i]);
|
||||
return false;
|
||||
config->strValues[i] = strdup(config_str_default[i]);
|
||||
}
|
||||
|
||||
}
|
||||
for (int i = CONF_INT_MIN + 1; i < CONF_INT_MAX; i++) {
|
||||
|
||||
for (int i = 0; i < CONF_INT_MAX; i++) {
|
||||
char *ptr;
|
||||
ptr = nc_hashmap_get(nc_hashmap_get(keyfile, "settings"), config_key_int[i]);
|
||||
if (ptr) {
|
||||
errno = 0;
|
||||
config->intValues[i] = strtoll(ptr, NULL, 10);
|
||||
if (errno != 0) {
|
||||
telem_log(LOG_ERR, "Error while parsing value of option %s: %s\n",
|
||||
config_key_int[i], strerror(errno));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "ERR: missing key with integer value: %s\n", config_key_int[i]);
|
||||
return false;
|
||||
config->intValues[i] = config_int_default[i];
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = CONF_BOOL_MIN + 1; i < CONF_BOOL_MAX; i++) {
|
||||
for (int i = 0; i < CONF_BOOL_MAX; i++) {
|
||||
char *ptr;
|
||||
ptr = nc_hashmap_get(nc_hashmap_get(keyfile, "settings"), config_key_bool[i]);
|
||||
config->boolValues[i] = false;
|
||||
|
||||
if (ptr) {
|
||||
if (strcasecmp(ptr, "TRUE") == 0) {
|
||||
if ((strcasecmp(ptr, "TRUE") == 0) || (strcmp(ptr, "1") == 0)) {
|
||||
config->boolValues[i] = true;
|
||||
}
|
||||
if (strcasecmp(ptr, "1") == 0) {
|
||||
config->boolValues[i] = true;
|
||||
}
|
||||
} else {
|
||||
/* 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 if ((strcasecmp(ptr, "FALSE") == 0) || (strcmp(ptr, "0") == 0)) {
|
||||
config->boolValues[i] = false;
|
||||
} else {
|
||||
fprintf(stderr, "ERR: missing key with boolean value: %s\n", config_key_bool[i]);
|
||||
telem_log(LOG_ERR, "Configuration item '%s' requires a boolean value\n",
|
||||
config_key_bool[i]);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
config->boolValues[i] = config_bool_default[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
config->initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void initialize_config(void)
|
||||
static void initialize_config(void)
|
||||
{
|
||||
if (config.initialized) {
|
||||
return;
|
||||
@@ -175,26 +228,25 @@ void initialize_config(void)
|
||||
if (access(etc_config_file, R_OK) == 0) {
|
||||
config_file = etc_config_file;
|
||||
} else {
|
||||
if (access(default_config_file,
|
||||
R_OK) == 0) {
|
||||
if (access(default_config_file, R_OK) == 0) {
|
||||
config_file = default_config_file;
|
||||
} else {
|
||||
/* If there is no default config, exit with failure */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "ERR: No configuration file"
|
||||
" found, exiting\n");
|
||||
#endif
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!read_config_from_file(config_file, &config)) {
|
||||
/* Error while parsing file */
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "ERR: Error while parsing configuration file\n");
|
||||
#endif
|
||||
exit(EXIT_FAILURE);
|
||||
|
||||
if (config_file) {
|
||||
if (!read_config_from_file(config_file, &config)) {
|
||||
/* Error while parsing file */
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!set_default_config_values(&config)) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
config.initialized = true;
|
||||
}
|
||||
|
||||
void reload_config(void)
|
||||
@@ -214,7 +266,7 @@ void free_configuration(void)
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = CONF_STR_MIN + 1; i < CONF_STR_MAX; i++) {
|
||||
for (int i = 0; i < CONF_STR_MAX; i++) {
|
||||
free(config.strValues[i]);
|
||||
}
|
||||
|
||||
|
||||
+33
-8
@@ -18,13 +18,31 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Default configuration settings */
|
||||
#define DEFAULT_SERVER_ADDR BACKEND_ADDR
|
||||
#define DEFAULT_SOCKET_PATH "/run/telem-0"
|
||||
#define DEFAULT_SPOOL_DIR LOCALSTATEDIR "/spool/telemetry"
|
||||
#define DEFAULT_RATE_LIMIT_STRATEGY "spool"
|
||||
#define DEFAULT_CAINFO ""
|
||||
#define DEFAULT_TIDHEADER "X-Telemetry-TID: 6907c830-eed9-4ce9-81ae-76daf8d88f0f"
|
||||
|
||||
#define DEFAULT_RECORD_EXPIRY 1200
|
||||
#define DEFAULT_SPOOL_MAX_SIZE 5120
|
||||
#define DEFAULT_SPOOL_PROCESS_TIME 120
|
||||
#define DEFAULT_RECORD_WINDOW_LENGTH 15
|
||||
#define DEFAULT_BYTE_WINDOW_LENGTH 20
|
||||
#define DEFAULT_RECORD_BURST_LIMIT 1000
|
||||
#define DEFAULT_BYTE_BURST_LIMIT -1
|
||||
|
||||
#define DEFAULT_RATE_LIMIT_ENABLED true
|
||||
#define DEFAULT_DAEMON_RECYCLING_ENABLED true
|
||||
#define DEFAULT_RECORD_RETENTION_ENABLED false
|
||||
#define DEFAULT_RECORD_SERVER_DELIVERY_ENABLED true
|
||||
|
||||
#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,
|
||||
CONF_SERVER_ADDR,
|
||||
CONF_SERVER_ADDR = 0,
|
||||
CONF_SOCKET_PATH,
|
||||
CONF_SPOOL_DIR,
|
||||
CONF_RATE_LIMIT_STRATEGY,
|
||||
@@ -34,8 +52,7 @@ enum config_str_keys {
|
||||
};
|
||||
|
||||
enum config_int_keys {
|
||||
CONF_INT_MIN = 0,
|
||||
CONF_RECORD_EXPIRY,
|
||||
CONF_RECORD_EXPIRY = 0,
|
||||
CONF_SPOOL_MAX_SIZE,
|
||||
CONF_SPOOL_PROCESS_TIME,
|
||||
CONF_RECORD_WINDOW_LENGTH,
|
||||
@@ -46,8 +63,7 @@ enum config_int_keys {
|
||||
};
|
||||
|
||||
enum config_bool_keys {
|
||||
CONF_BOOL_MIN = 0,
|
||||
CONF_RATE_LIMIT_ENABLED,
|
||||
CONF_RATE_LIMIT_ENABLED = 0,
|
||||
CONF_DAEMON_RECYCLING_ENABLED,
|
||||
CONF_RECORD_RETENTION_ENABLED,
|
||||
CONF_RECORD_SERVER_DELIVERY_ENABLED,
|
||||
@@ -65,6 +81,15 @@ typedef struct configuration {
|
||||
/* Sets the configuration file to be used later */
|
||||
int set_config_file(const char *filename);
|
||||
|
||||
/* Gets the configuration currently in use */
|
||||
const char *get_config_file(void);
|
||||
|
||||
/* Gets the configuration specified via command line or NULL */
|
||||
const char *get_cmd_line_config_file(void);
|
||||
|
||||
/* Sets all default configuration values to a given config */
|
||||
bool set_default_config_values(struct configuration *config);
|
||||
|
||||
/* Parses the ini format config file */
|
||||
bool read_config_from_file(char *filename, struct configuration *config);
|
||||
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
[Unit]
|
||||
Description=Telemetrics BERT Probe
|
||||
Requires=telemprobd.socket
|
||||
After=telemprobd.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,4 @@
|
||||
[settings]
|
||||
server=http://127.0.0.1
|
||||
|
||||
cainfo=/tmp/cacert.crt
|
||||
@@ -2,7 +2,7 @@
|
||||
Description=Telemetrics Heartbeat Probe
|
||||
Requires=telemprobd.socket
|
||||
After=telemprobd.socket
|
||||
ConditionPathExists=!/etc/telemetrics/opt-out
|
||||
ConditionPathExists=/etc/telemetrics/opt-in
|
||||
|
||||
[Service]
|
||||
ExecStart=@bindir@/hprobe -Hlu
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[Unit]
|
||||
Description=Daily Heartbeat for Telemetrics
|
||||
ConditionPathExists=!/etc/telemetrics/opt-out
|
||||
ConditionPathExists=/etc/telemetrics/opt-in
|
||||
|
||||
[Timer]
|
||||
OnCalendar=daily
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Description=Telemetrics Systemd Journal Probe
|
||||
Requires=telemprobd.socket
|
||||
After=telemprobd.socket
|
||||
ConditionPathExists=!/etc/telemetrics/opt-out
|
||||
ConditionPathExists=/etc/telemetrics/opt-in
|
||||
|
||||
[Service]
|
||||
ExecStart=@bindir@/journalprobe -t
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Description=Telemetrics Systemd Journal Probe
|
||||
Requires=telemprobd.socket
|
||||
After=telemprobd.socket
|
||||
ConditionPathExists=!/etc/telemetrics/opt-out
|
||||
ConditionPathExists=/etc/telemetrics/opt-in
|
||||
|
||||
[Service]
|
||||
ExecStart=@bindir@/journalprobe
|
||||
|
||||
+3
-19
@@ -5,20 +5,19 @@ pathfix = @sed \
|
||||
-e 's|@localstatedir[@]|$(localstatedir)|g' \
|
||||
-e 's|@PACKAGE_VERSION[@]|$(PACKAGE_VERSION)|g' \
|
||||
-e 's|@SOCKETDIR[@]|$(SOCKETDIR)|g' \
|
||||
-e 's|@systemctldir[@]|$(SYSTEMD_SYSTEMCTLDIR)|g'
|
||||
-e 's|@systemctldir[@]|$(SYSTEMD_SYSTEMCTLDIR)|g' \
|
||||
-e 's|@BACKEND_ADDR[@]|$(BACKEND_ADDR)|g'
|
||||
|
||||
EXTRA_DIST += \
|
||||
%D%/40-core-ulimit.conf \
|
||||
%D%/40-crash-probe.conf.in \
|
||||
%D%/example.conf \
|
||||
%D%/example.1.conf \
|
||||
%D%/example.2.conf \
|
||||
%D%/hprobe.service.in \
|
||||
%D%/hprobe.timer \
|
||||
%D%/bert-probe.service.in \
|
||||
%D%/journal-probe.service.in \
|
||||
%D%/journal-probe-tail.service.in \
|
||||
%D%/python-probe.service.in \
|
||||
%D%/python-probe.path.in \
|
||||
%D%/pstore-probe.service.in \
|
||||
%D%/klogscanner.service.in \
|
||||
%D%/pstore-clean.service.in \
|
||||
@@ -53,11 +52,8 @@ systemdunitdir = @SYSTEMD_UNITDIR@
|
||||
systemdunit_DATA = \
|
||||
%D%/hprobe.service \
|
||||
%D%/hprobe.timer \
|
||||
%D%/bert-probe.service \
|
||||
%D%/journal-probe.service \
|
||||
%D%/journal-probe-tail.service \
|
||||
%D%/python-probe.service \
|
||||
%D%/python-probe.path \
|
||||
%D%/pstore-probe.service \
|
||||
%D%/klogscanner.service \
|
||||
%D%/pstore-clean.service \
|
||||
@@ -70,9 +66,6 @@ systemdunit_DATA = \
|
||||
%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) < $< > $@
|
||||
|
||||
@@ -94,12 +87,6 @@ systemdunit_DATA = \
|
||||
%D%/telempostd.service: %D%/telempostd.service.in
|
||||
$(pathfix) < $< > $@
|
||||
|
||||
%D%/python-probe.service: %D%/python-probe.service.in
|
||||
$(pathfix) < $< > $@
|
||||
|
||||
%D%/python-probe.path: %D%/python-probe.path.in
|
||||
$(pathfix) < $< > $@
|
||||
|
||||
%D%/telemprobd.service: %D%/telemprobd.service.in
|
||||
$(pathfix) < $< > $@
|
||||
|
||||
@@ -123,8 +110,6 @@ clean-local:
|
||||
%D%/telemprobd.socket \
|
||||
%D%/telempostd.service \
|
||||
%D%/telempostd.path \
|
||||
%D%/python-probe.service \
|
||||
%D%/python-probe.path \
|
||||
%D%/telemprobd-update-trigger.service \
|
||||
%D%/telemetrics.conf \
|
||||
%D%/telemetrics-dirs.conf \
|
||||
@@ -136,5 +121,4 @@ clean-local:
|
||||
%D%/klogscanner.service \
|
||||
%D%/pstore-clean.service \
|
||||
%D%/hprobe.service \
|
||||
%D%/bert-probe.service \
|
||||
%D%/.dirstamp
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
Description=Telemetrics Pstore Probe
|
||||
Requires=telemprobd.socket
|
||||
After=telemprobd.socket
|
||||
ConditionPathExists=/etc/telemetrics/opt-in
|
||||
|
||||
[Service]
|
||||
ExecStart=@bindir@/pstoreprobe
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
[Unit]
|
||||
Description=Python Probe Daemon Staging
|
||||
ConditionPathExists=!/etc/telemetrics/opt-out
|
||||
|
||||
[Path]
|
||||
DirectoryNotEmpty=/var/lib/telemetry/python
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -1,13 +0,0 @@
|
||||
[Unit]
|
||||
Description=Telemetrics Python Probe
|
||||
Requires=telemprobd.socket
|
||||
After=telemprobd.socket
|
||||
ConditionPathExists=!/etc/telemetrics/opt-out
|
||||
|
||||
[Service]
|
||||
User=telemetry
|
||||
ExecStart=@bindir@/pythonprobe
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
@@ -4,5 +4,3 @@ 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/pstore 0750 telemetry telemetry -
|
||||
d /var/lib/telemetry/python 01777 telemetry telemetry -
|
||||
d /var/tmp/telemetry 01777 telemetry telemetry -
|
||||
|
||||
@@ -1,67 +1,69 @@
|
||||
# values represent their default state
|
||||
# copy to /etc/telemetrics/telemetrics.conf and modify for user config
|
||||
[settings]
|
||||
# ip address of destination server for record delivery
|
||||
server=https://clr.telemetry.intel.com/v2/collector
|
||||
#server=@BACKEND_ADDR@
|
||||
|
||||
socket_path=@SOCKETDIR@/telem-0
|
||||
#socket_path=@SOCKETDIR@/telem-0
|
||||
|
||||
# certificate file to use to validate ssl endpoint
|
||||
cainfo=
|
||||
#cainfo=
|
||||
|
||||
# Telemetry id - post header used to group records in ingestion service,
|
||||
# which may be ingesting for more than one set of clients. Can be set
|
||||
# to any string.
|
||||
tidheader=X-Telemetry-TID:\s6907c830-eed9-4ce9-81ae-76daf8d88f0f
|
||||
#tidheader=X-Telemetry-TID:\s6907c830-eed9-4ce9-81ae-76daf8d88f0f
|
||||
|
||||
# record expiry time in minutes
|
||||
record_expiry=1200
|
||||
#record_expiry=1200
|
||||
|
||||
spool_dir=@localstatedir@/spool/telemetry
|
||||
#spool_dir=@localstatedir@/spool/telemetry
|
||||
|
||||
# maximum size of the spool directory in KB, -1 = quota disabled.
|
||||
# The block size of the files in this directory is considered,
|
||||
# and not the actual size of the record itself.
|
||||
spool_max_size=5120
|
||||
#spool_max_size=5120
|
||||
|
||||
# time in seconds for processing spool
|
||||
# Valid range: 120..300. Values outside this range are clamped.
|
||||
spool_process_time=120
|
||||
#spool_process_time=120
|
||||
|
||||
# rate limit enabled - if this is set to false then all rate-limiting disabled.
|
||||
# It is possible to disable each rate-limit individually below.
|
||||
rate_limit_enabled=true
|
||||
#rate_limit_enabled=true
|
||||
|
||||
# rate limiting record burst limit
|
||||
# Valid Range: 0..INT_MAX, -1 = disabled.
|
||||
record_burst_limit=1000
|
||||
#record_burst_limit=1000
|
||||
|
||||
# rate limiting record window length in minutes
|
||||
# Valid Range: 0..59
|
||||
record_window_length=15
|
||||
#record_window_length=15
|
||||
|
||||
# rate limiting byte burst limit
|
||||
# Valid Range: 0..INT_MAX, -1 = disabled.
|
||||
byte_burst_limit=-1
|
||||
#byte_burst_limit=-1
|
||||
|
||||
# rate limiting byte window length in minutes
|
||||
# Valid Range: 0..59
|
||||
byte_window_length=20
|
||||
#byte_window_length=20
|
||||
|
||||
# rate limit strategy - what to do with record if rate-limiting prevents
|
||||
# delivery over network
|
||||
# Valid stategies: spool, drop
|
||||
rate_limit_strategy=spool
|
||||
#rate_limit_strategy=spool
|
||||
|
||||
# daemon recycling enabled - if daemon has been running for a while (2 hours),
|
||||
# has not any client nor spool data, then it exits.
|
||||
# this is to ensure that latest code runs.
|
||||
daemon_recycling_enabled=true
|
||||
#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_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
|
||||
#record_retention_enabled=false
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[Unit]
|
||||
Description=Telemetry Post Daemon staging
|
||||
ConditionPathExists=!/etc/telemetrics/opt-out
|
||||
ConditionPathExists=/etc/telemetrics/opt-in
|
||||
|
||||
[Path]
|
||||
DirectoryNotEmpty=@localstatedir@/spool/telemetry
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[Unit]
|
||||
Description=Telemetrics Post Daemon
|
||||
ConditionPathExists=!/etc/telemetrics/opt-out
|
||||
ConditionPathExists=/etc/telemetrics/opt-in
|
||||
|
||||
[Service]
|
||||
ExecStart=@bindir@/telempostd
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[Unit]
|
||||
Description=Telemetrics Daemon
|
||||
ConditionPathExists=!/etc/telemetrics/opt-out
|
||||
ConditionPathExists=/etc/telemetrics/opt-in
|
||||
|
||||
[Service]
|
||||
ExecStart=@bindir@/telemprobd
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[Unit]
|
||||
Description=Telemetrics Daemon
|
||||
ConditionPathExists=!/etc/telemetrics/opt-out
|
||||
ConditionPathExists=/etc/telemetrics/opt-in
|
||||
|
||||
[Socket]
|
||||
ListenStream=@SOCKETDIR@/telem-0
|
||||
|
||||
+40
-59
@@ -41,69 +41,19 @@ bool _fgets(char *s, int n, FILE *stream)
|
||||
return true;
|
||||
}
|
||||
|
||||
void stage_record(char *filepath, char *headers[], char *body)
|
||||
bool read_record(char *fullpath, char *headers[], char **body, char **cfg_file)
|
||||
{
|
||||
int tmpfd;
|
||||
FILE *tmpfile = NULL;
|
||||
|
||||
// Use default path if not provided
|
||||
if (filepath == NULL) {
|
||||
telem_log(LOG_ERR, "filepath value must be provided, aborting\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
tmpfd = mkstemp(filepath);
|
||||
if (!tmpfd) {
|
||||
telem_perror("Error opening staging file");
|
||||
close(tmpfd);
|
||||
if (unlink(filepath)) {
|
||||
telem_perror("Error deleting staging file");
|
||||
}
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
// open file
|
||||
tmpfile = fdopen(tmpfd, "a");
|
||||
if (!tmpfile) {
|
||||
telem_perror("Error opening temp stage file");
|
||||
close(tmpfd);
|
||||
if (unlink(filepath)) {
|
||||
telem_perror("Error deleting temp stage file");
|
||||
}
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
// write headers
|
||||
for (int i = 0; i < NUM_HEADERS; i++) {
|
||||
fprintf(tmpfile, "%s\n", headers[i]);
|
||||
}
|
||||
|
||||
//write body
|
||||
fprintf(tmpfile, "%s\n", body);
|
||||
fflush(tmpfile);
|
||||
fclose(tmpfile);
|
||||
|
||||
clean_exit:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool read_record(char *fullpath, char *headers[], char **body)
|
||||
{
|
||||
int i, ret = 0;
|
||||
int i = 0;
|
||||
bool result = false;
|
||||
FILE *fp = NULL;
|
||||
long offset;
|
||||
char line[LINE_MAX] = { 0 };
|
||||
struct stat buf;
|
||||
#if (LINE_MAX > PATH_MAX)
|
||||
char line[LINE_MAX+1] = { 0 };
|
||||
#else
|
||||
char line[PATH_MAX+1] = { 0 };
|
||||
#endif
|
||||
long size;
|
||||
|
||||
ret = stat(fullpath, &buf);
|
||||
if (ret == -1) {
|
||||
telem_log(LOG_ERR, "Unable to stat record %s in staging\n", fullpath);
|
||||
return false;
|
||||
}
|
||||
size = buf.st_size;
|
||||
uint32_t cfg_prefix = 0;
|
||||
|
||||
fp = fopen(fullpath, "r");
|
||||
if (fp == NULL) {
|
||||
@@ -111,9 +61,40 @@ bool read_record(char *fullpath, char *headers[], char **body)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the file size
|
||||
fseek(fp, 0 , SEEK_END);
|
||||
size = ftell(fp);
|
||||
fseek(fp, 0 , SEEK_SET);
|
||||
|
||||
// First line may contain configuration file path
|
||||
if (fread(&cfg_prefix, CFG_PREFIX_LENGTH, 1, fp) != 1) {
|
||||
telem_log(LOG_ERR, "Error while parsing staged record configuration info.\n");
|
||||
goto read_error;
|
||||
}
|
||||
|
||||
if (cfg_prefix == CFG_PREFIX_32BIT) {
|
||||
if (!_fgets(line, sizeof(line), fp)) {
|
||||
telem_log(LOG_ERR, "Error while parsing staged record [%x]\n", cfg_prefix);
|
||||
goto read_error;
|
||||
}
|
||||
|
||||
size_t pathlen = strlen(line);
|
||||
*cfg_file = malloc(pathlen + 1);
|
||||
if (*cfg_file == NULL) {
|
||||
telem_log(LOG_ERR, "Could not allocate memory for config file path\n");
|
||||
goto read_error;
|
||||
}
|
||||
strcpy (*cfg_file, line);
|
||||
telem_debug("DEBUG: cfg_file specified: %s\n", *cfg_file);
|
||||
} else {
|
||||
telem_debug("DEBUG: no user cfg file specified, cfg_prefix: %08x\n", cfg_prefix);
|
||||
*cfg_file = NULL;
|
||||
rewind(fp);
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_HEADERS; i++) {
|
||||
const char *header_name = get_header_name(i);
|
||||
if (!_fgets(line, LINE_MAX, fp)) {
|
||||
if (!_fgets(line, sizeof(line), fp)) {
|
||||
telem_log(LOG_ERR, "Error while parsing staged record\n");
|
||||
fclose(fp);
|
||||
return false;
|
||||
|
||||
+1
-11
@@ -16,16 +16,6 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
/**
|
||||
* Save a telemetry record to disk
|
||||
*
|
||||
* @param path pointer to a directory to save record
|
||||
* @param headers pointer to array of headers and values
|
||||
* @param body record message content
|
||||
*
|
||||
*/
|
||||
void stage_record(char *path, char *headers[], char *body);
|
||||
|
||||
/**
|
||||
* Reads a telemetry record
|
||||
*
|
||||
@@ -35,4 +25,4 @@ void stage_record(char *path, char *headers[], char *body);
|
||||
*
|
||||
* @return true if successful otherwise false
|
||||
*/
|
||||
bool read_record(char *fullpath, char *headers[], char **body);
|
||||
bool read_record(char *fullpath, char *headers[], char **body, char **cfg);
|
||||
|
||||
+12
-9
@@ -24,14 +24,18 @@
|
||||
#include "common.h"
|
||||
#include "journal.h"
|
||||
|
||||
void print_usage(void)
|
||||
static void print_usage(void)
|
||||
{
|
||||
printf(" Usage\n");
|
||||
printf("Usage:\n");
|
||||
printf(" telem_journal [-Vi] [-r <record_id>] [-e <event_id>] [-c <classification>] [-b <boot_id>]\n\n");
|
||||
printf("Where:\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(" -i, --include_record Include record content if available.\n");
|
||||
printf(" Content only available when telemetry is configured\n");
|
||||
printf(" with \"record_retention_enabled=true\"\n");
|
||||
printf(" -V, --verbose Verbose output\n");
|
||||
printf(" -h, --help Display this help message\n");
|
||||
}
|
||||
@@ -41,8 +45,8 @@ int main(int argc, char **argv)
|
||||
|
||||
int rc = EXIT_SUCCESS;
|
||||
int count = 0;
|
||||
int verbose_output = 0;
|
||||
int record = 0;
|
||||
bool verbose_output = false;
|
||||
bool record = false;
|
||||
char *boot_id = NULL;
|
||||
char *record_id = NULL;
|
||||
char *event_id = NULL;
|
||||
@@ -78,16 +82,15 @@ int main(int argc, char **argv)
|
||||
boot_id = optarg;
|
||||
break;
|
||||
case 'V':
|
||||
verbose_output = 1;
|
||||
verbose_output = true;
|
||||
break;
|
||||
case 'i':
|
||||
record = 1;
|
||||
record = true;
|
||||
break;
|
||||
case 'h':
|
||||
print_usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
case '?':
|
||||
/** default */
|
||||
default:
|
||||
print_usage();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+38
-69
@@ -58,9 +58,7 @@ static int serialize_journal_entry(struct JournalEntry *entry, char **buff)
|
||||
|
||||
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
|
||||
telem_log(LOG_ERR, "Error: Unable to serialize data in buff\n");
|
||||
rc = -1;
|
||||
}
|
||||
|
||||
@@ -101,11 +99,14 @@ static int deserialize_journal_entry(char *line, struct JournalEntry **entry)
|
||||
size_t offset = 0;
|
||||
struct JournalEntry *e = NULL;
|
||||
|
||||
if (line == NULL) {
|
||||
/* Assume an error... */
|
||||
*entry = NULL;
|
||||
|
||||
if (line == NULL || !strlen(line)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
e = malloc(sizeof(struct JournalEntry));
|
||||
e = calloc(1, sizeof(struct JournalEntry));
|
||||
if (!e) {
|
||||
return -1;
|
||||
}
|
||||
@@ -140,10 +141,6 @@ static int deserialize_journal_entry(char *line, struct JournalEntry **entry)
|
||||
e->boot_id = out;
|
||||
rc = 0;
|
||||
break;
|
||||
default:
|
||||
assert(i < 0 && i > 4);
|
||||
free(out);
|
||||
rc = 1;
|
||||
}
|
||||
} else {
|
||||
rc = -1;
|
||||
@@ -204,9 +201,7 @@ static int save_entry(FILE *fptr, struct JournalEntry *entry)
|
||||
}
|
||||
|
||||
if ((rc = serialize_journal_entry(entry, &serialized_data)) == 0) {
|
||||
#ifdef DEBUG
|
||||
printf("Saving: %s\n", serialized_data);
|
||||
#endif
|
||||
telem_debug("DEBUG: Saving: %s\n", serialized_data);
|
||||
fprintf(fptr, "%s\n", serialized_data);
|
||||
fflush(fptr);
|
||||
free(serialized_data);
|
||||
@@ -229,9 +224,7 @@ static int read_boot_id(char buff[])
|
||||
|
||||
fs = fopen(BOOTID_FILE, "r");
|
||||
if (!fs) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Unable to open %s for reading: %d\n", BOOTID_FILE, errno);
|
||||
#endif
|
||||
telem_log(LOG_ERR, "Error: Unable to open %s for reading: %d\n", BOOTID_FILE, errno);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -264,9 +257,7 @@ static int skip_n_lines(int n, FILE *fptr, int (*found_record)(char *))
|
||||
struct JournalEntry *entry = NULL;
|
||||
|
||||
if (fptr == NULL) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "fptr argument to skip_n_lines is invalid\n");
|
||||
#endif
|
||||
telem_log(LOG_ERR, "fptr argument to skip_n_lines is invalid\n");
|
||||
// File descriptor in bad state
|
||||
return EBADFD;
|
||||
}
|
||||
@@ -281,6 +272,8 @@ static int skip_n_lines(int n, FILE *fptr, int (*found_record)(char *))
|
||||
break;
|
||||
}
|
||||
if (found_record != NULL) {
|
||||
if (!strlen(line))
|
||||
continue;
|
||||
deserialize_journal_entry(line, &entry);
|
||||
if (entry) {
|
||||
found_record(entry->record_id);
|
||||
@@ -327,9 +320,7 @@ static int copy_to_tmp(FILE *fptr, char *tmp_path)
|
||||
|
||||
if (fclose(fptr_tmp) != 0) {
|
||||
rc = errno;
|
||||
#ifdef DEBUG
|
||||
perror("Error: ");
|
||||
#endif
|
||||
telem_perror("Error");
|
||||
}
|
||||
free(line);
|
||||
|
||||
@@ -350,22 +341,20 @@ TelemJournal *open_journal(const char *journal_file)
|
||||
fptr = fopen(journal_file, "a+");
|
||||
}
|
||||
if (fptr == NULL) {
|
||||
#ifdef DEBUG
|
||||
perror("Error while opening journal file: ");
|
||||
#endif
|
||||
telem_perror("Error while opening journal file");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (read_boot_id(boot_id) != 0) {
|
||||
#ifdef DEBUG
|
||||
perror("Error while reading boot_id: ");
|
||||
#endif
|
||||
telem_perror("Error while reading boot_id");
|
||||
fclose(fptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
telem_journal = malloc(sizeof(struct TelemJournal));
|
||||
if (!telem_journal) {
|
||||
fprintf(stderr, "Unable to allocate more memory\n");
|
||||
telem_log(LOG_CRIT, "CRIT: Unable to allocate memory\n");
|
||||
fclose(fptr);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -379,9 +368,7 @@ TelemJournal *open_journal(const char *journal_file)
|
||||
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
|
||||
telem_debug("Records in db: %d\n", telem_journal->record_count);
|
||||
|
||||
return telem_journal;
|
||||
}
|
||||
@@ -433,7 +420,7 @@ static void print_record(char *record_id)
|
||||
|
||||
recordfp = fopen(filepath, "r");
|
||||
if (!recordfp) {
|
||||
telem_perror("Error when opening a record to print");
|
||||
telem_log(LOG_INFO, "Could not open record %s: %s\n", record_id, strerror(errno));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -476,11 +463,13 @@ int print_journal(TelemJournal *telem_journal, char *classification,
|
||||
if (rc == -1) {
|
||||
return rc;
|
||||
} else if (rc != 0) {
|
||||
fprintf(stderr, "An error occurred while advancing journal file: %s\n", strerror(rc));
|
||||
telem_log(LOG_ERR, "An error occurred while advancing journal file: %s\n", strerror(rc));
|
||||
}
|
||||
}
|
||||
|
||||
while (getline(&line, &len, journal_fileptr) != -1) {
|
||||
if (!strlen(line))
|
||||
continue;
|
||||
deserialize_journal_entry(line, &entry);
|
||||
if (entry) {
|
||||
/* filter entry out if one is provided */
|
||||
@@ -498,16 +487,16 @@ int print_journal(TelemJournal *telem_journal, char *classification,
|
||||
// Check prefixes when classification ends in /*, otherwise use strcomp
|
||||
if (is_class_prefix(classification)) {
|
||||
if (strncmp(entry->classification, classification, strlen(classification) - 1) != 0) {
|
||||
continue;
|
||||
goto skip_print;
|
||||
}
|
||||
} else if (strcmp(entry->classification, classification) != 0) {
|
||||
continue;
|
||||
goto skip_print;
|
||||
}
|
||||
}
|
||||
/* 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;
|
||||
goto skip_print;
|
||||
}
|
||||
/* print record metadata */
|
||||
fprintf(stdout, "%-30s %s %s %s %s\n", entry->classification, str_time, entry->record_id, entry->event_id, entry->boot_id);
|
||||
@@ -516,9 +505,9 @@ int print_journal(TelemJournal *telem_journal, char *classification,
|
||||
print_record(entry->record_id);
|
||||
}
|
||||
count++;
|
||||
}
|
||||
skip_print:
|
||||
free_journal_entry(entry);
|
||||
free_journal_entry(entry);
|
||||
}
|
||||
}
|
||||
free(line);
|
||||
fclose(journal_fileptr);
|
||||
@@ -563,9 +552,7 @@ int new_journal_entry(TelemJournal *telem_journal, char *classification,
|
||||
struct JournalEntry *entry = NULL;
|
||||
|
||||
if (telem_journal == NULL) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Error: telem_journal was not initialized\n");
|
||||
#endif
|
||||
telem_log(LOG_ERR, "telem_journal was not initialized\n");
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -579,7 +566,7 @@ int new_journal_entry(TelemJournal *telem_journal, char *classification,
|
||||
|
||||
entry = malloc(sizeof(struct JournalEntry));
|
||||
if (!entry) {
|
||||
fprintf(stderr, "Error: unable to allocate more memory\n");
|
||||
telem_log(LOG_CRIT, "CRIT: unable to allocate memory\n");
|
||||
return rc;
|
||||
}
|
||||
entry->classification = NULL;
|
||||
@@ -588,16 +575,12 @@ int new_journal_entry(TelemJournal *telem_journal, char *classification,
|
||||
entry->boot_id = NULL;
|
||||
|
||||
if (get_random_id(&record_id) != 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Error: unable to generate random id\n");
|
||||
#endif
|
||||
telem_log(LOG_ERR, "Erorr: Unable to generate random id\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
if (read_boot_id(boot_id) != 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Error: unable to read boot_id\n");
|
||||
#endif
|
||||
telem_log(LOG_ERR, "Error: Unable to read boot_id\n");
|
||||
goto quit;
|
||||
}
|
||||
|
||||
@@ -615,9 +598,7 @@ int new_journal_entry(TelemJournal *telem_journal, char *classification,
|
||||
|
||||
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
|
||||
telem_debug("DEBUG: %d records in journal\n", telem_journal->record_count);
|
||||
}
|
||||
|
||||
free(telem_journal->latest_record_id);
|
||||
@@ -647,9 +628,7 @@ int prune_journal(struct TelemJournal *telem_journal, char *tmp_dir)
|
||||
|
||||
// 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
|
||||
telem_log(LOG_ERR, "Error skipping %d journal lines\n", count);
|
||||
// if rc == -1 (n > #lines in file, change to errno style)
|
||||
return (rc == -1) ? EADDRNOTAVAIL : rc;
|
||||
}
|
||||
@@ -665,38 +644,28 @@ int prune_journal(struct TelemJournal *telem_journal, char *tmp_dir)
|
||||
}
|
||||
// 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
|
||||
telem_log(LOG_ERR, "Error copying partial journal to temp journal file\n");
|
||||
goto quit;
|
||||
}
|
||||
// close file handler
|
||||
if ((rc = fclose(telem_journal->fptr)) != 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "Error: closing journal file handler\n");
|
||||
#endif
|
||||
telem_log(LOG_ERR, "Error closing journal file handler\n");
|
||||
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
|
||||
telem_log(LOG_ERR, "Error while overwriting journal file\n");
|
||||
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
|
||||
telem_log(LOG_ERR, "Error re-opening journal file\n");
|
||||
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
|
||||
telem_debug("DEBUG: record_count: %d\n", telem_journal->record_count);
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
|
||||
@@ -5,5 +5,11 @@ bin_PROGRAMS += \
|
||||
%D%/journal.c \
|
||||
src/util.c \
|
||||
src/common.c
|
||||
%C%_telem_journal_CFLAGS = \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
if LOG_SYSTEMD
|
||||
%C%_telem_journal_CFLAGS += $(SYSTEMD_JOURNAL_CFLAGS)
|
||||
%C%_telem_journal_LDADD = $(SYSTEMD_JOURNAL_LIBS)
|
||||
endif
|
||||
# vim: filetype=automake tabstop=8 shiftwidth=8 noexpandtab
|
||||
|
||||
+14
-5
@@ -1,12 +1,22 @@
|
||||
bin_PROGRAMS = \
|
||||
%D%/telemprobd \
|
||||
%D%/telempostd
|
||||
%D%/telempostd \
|
||||
%D%/telemctl
|
||||
|
||||
%C%_telemctl_SOURCES = \
|
||||
%D%/telemctl.c
|
||||
|
||||
%C%_telemctl_CFLAGS = \
|
||||
$(AM_CFLAGS)
|
||||
|
||||
%C%_telemctl_LDFLAGS = \
|
||||
$(AM_LDFLAGS) \
|
||||
-pie
|
||||
|
||||
%C%_telemprobd_SOURCES = \
|
||||
%D%/probe.c \
|
||||
%D%/telemdaemon.c \
|
||||
%D%/telemdaemon.h \
|
||||
%D%/iorecord.c \
|
||||
%D%/journal/journal.c \
|
||||
%D%/journal/journal.h
|
||||
|
||||
@@ -80,8 +90,8 @@ endif
|
||||
|
||||
# set library version info
|
||||
SHAREDLIB_CURRENT=4
|
||||
SHAREDLIB_REVISION=0
|
||||
SHAREDLIB_AGE=1
|
||||
SHAREDLIB_REVISION=1
|
||||
SHAREDLIB_AGE=0
|
||||
|
||||
noinst_LTLIBRARIES = %D%/libtelem-shared.la
|
||||
|
||||
@@ -91,7 +101,6 @@ 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
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This program is part of the Clear Linux Project
|
||||
*
|
||||
* Copyright 2015 Intel Corporation
|
||||
* Copyright 2019 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
|
||||
@@ -17,6 +17,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "config.h"
|
||||
|
||||
@@ -35,15 +36,14 @@
|
||||
#include <systemd/sd-journal.h>
|
||||
#endif
|
||||
#else
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <syslog.h>
|
||||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
#define telem_debug(...) do { \
|
||||
(telem_log(LOG_DEBUG, "%s():[%d]", __func__, __LINE__), \
|
||||
telem_log(LOG_DEBUG, __VA_ARGS__)); \
|
||||
telem_log(LOG_DEBUG, "%s():[%d] ", __func__, __LINE__); \
|
||||
telem_log(LOG_DEBUG, __VA_ARGS__); \
|
||||
} while (0);
|
||||
#else
|
||||
#define telem_debug(...) do {} while (0);
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
/*
|
||||
* 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: */
|
||||
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* 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);
|
||||
|
||||
+36
-24
@@ -151,33 +151,38 @@ static char *string_strip(char *str, ssize_t len, ssize_t *out_len)
|
||||
/* eat \s */
|
||||
static char *string_unescape(char *str)
|
||||
{
|
||||
char *c, *c1, *c2, *c3;;
|
||||
char *c, *c1, *c2, *c3;;
|
||||
|
||||
if (!str)
|
||||
return NULL;
|
||||
if (!str) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c = calloc(strlen(str) + 1, 1);
|
||||
c1 = c;
|
||||
c = calloc(strlen(str) + 1, 1);
|
||||
if (c == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
c2 = str;
|
||||
while (c2 && *c2 != 0) {
|
||||
c3 = c2 + 1;
|
||||
if (*c2 == '\\') {
|
||||
if (*c3 == 's') {
|
||||
*c = ' ';
|
||||
c++;
|
||||
c2 += 2;
|
||||
} else {
|
||||
c2++;
|
||||
}
|
||||
} else {
|
||||
*c = *c2;
|
||||
c++;
|
||||
c2++;
|
||||
}
|
||||
}
|
||||
c1 = c;
|
||||
|
||||
free(str);
|
||||
c2 = str;
|
||||
while (c2 && *c2 != 0) {
|
||||
c3 = c2 + 1;
|
||||
if (*c2 == '\\') {
|
||||
if (*c3 == 's') {
|
||||
*c = ' ';
|
||||
c++;
|
||||
c2 += 2;
|
||||
} else {
|
||||
c2++;
|
||||
}
|
||||
} else {
|
||||
*c = *c2;
|
||||
c++;
|
||||
c2++;
|
||||
}
|
||||
}
|
||||
|
||||
free(str);
|
||||
return c1;
|
||||
}
|
||||
|
||||
@@ -300,7 +305,14 @@ int nc_ini_file_parse_full(const char *path, NcHashmap **out_map, int *error_lin
|
||||
key = strdup(buf);
|
||||
key = string_chew_terminated(key);
|
||||
value = string_chew_terminated(value);
|
||||
value = string_unescape(value);
|
||||
if (value != NULL) {
|
||||
value = string_unescape(value);
|
||||
if (value == NULL) {
|
||||
err_ret = NC_INI_ERROR_INTERNAL;
|
||||
fprintf(stderr, "[inifile] Fatal! Out of memory\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (streq(key, "")) {
|
||||
err_ret = NC_INI_ERROR_EMPTY_KEY;
|
||||
|
||||
+8
-2
@@ -27,7 +27,13 @@
|
||||
#include "configuration.h"
|
||||
#include "telempostdaemon.h"
|
||||
|
||||
bool (*post_record_ptr)(char *[], char *) = post_record_http;
|
||||
/*
|
||||
* Using a function pointer for unit testing to isolate the call to actual post function.
|
||||
* The call to post the record to the server is stubbed out in the unit tests
|
||||
* using pointer to a fake function.
|
||||
*/
|
||||
|
||||
bool (*post_record_ptr)(char *[], char *, char *) = post_record_http;
|
||||
|
||||
void print_usage(char *prog)
|
||||
{
|
||||
@@ -72,7 +78,7 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
initialize_daemon(&daemon);
|
||||
initialize_post_daemon(&daemon);
|
||||
|
||||
daemon.current_spool_size = get_spool_dir_size();
|
||||
|
||||
|
||||
+3
-9
@@ -51,12 +51,6 @@
|
||||
#include "telemdaemon.h"
|
||||
#include "configuration.h"
|
||||
|
||||
/*
|
||||
* Using a function pointer for unit testing to isolate the call to actual post function.
|
||||
* The call to post the record to the server is stubbed out in the unit tests
|
||||
* using pointer to a fake function.
|
||||
*/
|
||||
|
||||
void print_usage(char *prog)
|
||||
{
|
||||
printf("%s: Usage\n", prog);
|
||||
@@ -111,7 +105,7 @@ int main(int argc, char **argv)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
initialize_daemon(&daemon);
|
||||
initialize_probe_daemon(&daemon);
|
||||
|
||||
sigemptyset(&mask);
|
||||
|
||||
@@ -249,8 +243,8 @@ int main(int argc, char **argv)
|
||||
}
|
||||
|
||||
if (fdsi.ssi_signo == SIGTERM || fdsi.ssi_signo == SIGINT) {
|
||||
telem_log(LOG_INFO, "Received either a \
|
||||
SIGINT/SIGTERM signal\n");
|
||||
telem_log(LOG_INFO, "Received either a "
|
||||
"SIGINT/SIGTERM signal\n");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
|
||||
The default probes provided along the telemetry client code are:
|
||||
|
||||
* bertprobe: this probe reports on the Boot Error Region Table if such
|
||||
entry is found in ```/sys/firmware/acpi/tables/BERT```.
|
||||
|
||||
* crashprobe: This probe processes core dump files. It can be registered as
|
||||
the kernel core file handler in /proc/sys/kernel/core_pattern.
|
||||
|
||||
@@ -15,12 +12,10 @@ The default probes provided along the telemetry client code are:
|
||||
from failed services.
|
||||
|
||||
* klogscanner: a probe to collect 'oops messages' when the kernel detects a
|
||||
problem.
|
||||
problem. Also reports errors in the Boot Error Region Table if detected.
|
||||
|
||||
* pstoreprobe: probe to collect messages left on pstore filesystem.
|
||||
|
||||
* pythonprobe: a probe that monitors Python generated traceback files.
|
||||
|
||||
* telem-record-gen: this is a "general-purpose probe" for sending custom
|
||||
records on-the-fly. This tool can be used stand alone or as a part of a
|
||||
script to implement a probe.
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* 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"
|
||||
#include "log.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");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct telem_ref *tm_handle = NULL;
|
||||
char *classification = (char *)telem_record_class;
|
||||
char *payload;
|
||||
int ret;
|
||||
|
||||
// Following vars are for arg parsing.
|
||||
int c;
|
||||
int opt_index = 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:hV", opts, &opt_index)) != -1) {
|
||||
switch (c) {
|
||||
case 'f':
|
||||
if (tm_set_config_file(optarg) != 0) {
|
||||
telem_log(LOG_ERR, "Configuration file"
|
||||
" path not valid\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'V':
|
||||
printf(PACKAGE_VERSION "\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
case '?':
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
payload = calloc(sizeof(char), MAX_PAYLOAD_LENGTH);
|
||||
if (!payload) {
|
||||
printf("Unable to allocate more memory.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (!(ret = nc_b64enc_filename(bert_record_file, payload, MAX_PAYLOAD_LENGTH))) {
|
||||
printf("Failed to read payload from: %s\n", bert_record_file);
|
||||
ret = EXIT_FAILURE;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((ret = tm_create_record(&tm_handle, severity, classification,
|
||||
payload_version)) < 0) {
|
||||
printf("Failed to create record: %s\n", strerror(-ret));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((ret = tm_set_payload(tm_handle, payload)) < 0) {
|
||||
printf("Failed to set record payload: %s\n", strerror(-ret));
|
||||
goto done;
|
||||
}
|
||||
|
||||
if ((ret = tm_send_record(tm_handle)) < 0) {
|
||||
printf("Failed to send record to daemon: %s\n", strerror(-ret));
|
||||
goto done;
|
||||
}
|
||||
|
||||
ret = EXIT_SUCCESS;
|
||||
done:
|
||||
free(payload);
|
||||
tm_free_record(tm_handle);
|
||||
tm_handle = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
|
||||
@@ -41,6 +41,8 @@
|
||||
#include "probe.h"
|
||||
#include "telemetry.h"
|
||||
|
||||
#define FRAMES_MAX 64
|
||||
|
||||
static Dwfl *d_core = NULL;
|
||||
|
||||
/*
|
||||
@@ -248,7 +250,7 @@ static int frame_cb(Dwfl_Frame *frame, void *userdata)
|
||||
" current frame: %s\n",
|
||||
dwfl_errmsg(-1));
|
||||
if (ret < 0) {
|
||||
return DWARF_CB_ABORT;
|
||||
errorstr = NULL;
|
||||
}
|
||||
return DWARF_CB_ABORT;
|
||||
}
|
||||
@@ -298,6 +300,12 @@ static int frame_cb(Dwfl_Frame *frame, void *userdata)
|
||||
}
|
||||
}
|
||||
nc_string_append_printf(*bt, "\n");
|
||||
|
||||
if (frame_counter >= FRAMES_MAX) {
|
||||
errorstr = NULL;
|
||||
return DWARF_CB_ABORT;
|
||||
}
|
||||
|
||||
return DWARF_CB_OK;
|
||||
}
|
||||
|
||||
@@ -390,6 +398,12 @@ static int process_corefile(nc_string **backtrace)
|
||||
*backtrace = nc_string_dup("");
|
||||
|
||||
if (dwfl_getthreads(d_core, thread_cb, backtrace) != DWARF_CB_OK) {
|
||||
/* We aborted unwinding, due to too many frames.
|
||||
* We don't consider this as an error.
|
||||
*/
|
||||
if (frame_counter >= FRAMES_MAX) {
|
||||
return 0;
|
||||
}
|
||||
/* When errors occur during the unwinding, we reach this point.
|
||||
* If an error string is set for the particular error, send an
|
||||
* "error" record to capture at least a partial backtrace if
|
||||
@@ -656,6 +670,11 @@ int main(int argc, char **argv)
|
||||
}
|
||||
}
|
||||
|
||||
if (frame_counter >= FRAMES_MAX) {
|
||||
telem_log(LOG_ERR, "Too many frames. Backtrace truncated.\n");
|
||||
nc_string_append_printf(header, "Too many frames. Backtrace truncated.\n");
|
||||
}
|
||||
|
||||
nc_string_prepend(backtrace, header->str);
|
||||
|
||||
if (!send_data(&backtrace, default_severity, clr_class)) {
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ static char *create_payload(unsigned options)
|
||||
|
||||
num_bundles = scandir("/usr/share/clear/bundles", &entries, nodots, alphasort);
|
||||
if (num_bundles < 0) {
|
||||
telem_log(LOG_ERR, "scandir failed: %s\n", strerror(errno));
|
||||
telem_perror("scandir failed");
|
||||
free(payload);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ int main(void)
|
||||
// Gets the size of the kernel ring buffer
|
||||
log_size = klogctl(SYSLOG_ACTION_SIZE_BUFFER, NULL, 0);
|
||||
if (log_size < 0) {
|
||||
telem_log(LOG_ERR, "Cannot read size of kernel ring buffer: %s\n", strerror(errno));
|
||||
telem_perror("Cannot read size of kernel ring buffer");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ int main(void)
|
||||
memset(bufp, 0, buflen);
|
||||
bytes_read = klogctl(SYSLOG_ACTION_READ, bufp, (int)buflen);
|
||||
if (bytes_read < 0) {
|
||||
telem_log(LOG_ERR, "Cannot read contents of kernel ring buffer: %s\n", strerror(errno));
|
||||
telem_perror("Cannot read contents of kernel ring buffer");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+15
-12
@@ -23,6 +23,7 @@
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "log.h"
|
||||
#include "oops_parser.h"
|
||||
#include "klog_scanner.h"
|
||||
@@ -44,6 +45,11 @@ static bool send_data(char *backtrace, char *class, uint32_t severity)
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Truncate payload if necessary, otherwise nothing will be sent */
|
||||
if (strlen(backtrace) > MAX_PAYLOAD_LENGTH) {
|
||||
backtrace[MAX_PAYLOAD_LENGTH-1] = 0;
|
||||
}
|
||||
|
||||
if ((ret = tm_set_payload(handle, backtrace)) < 0) {
|
||||
telem_log(LOG_ERR, "Failed to set payload: %s", strerror(-ret));
|
||||
tm_free_record(handle);
|
||||
@@ -91,10 +97,8 @@ void split_buf_by_line(char *bufp, int bytes)
|
||||
start[linelength] = '\0';
|
||||
parse_single_line(start, linelength);
|
||||
if (oops_processed == true) {
|
||||
#ifdef DEBUG
|
||||
printf("[%s] oops_processed detected !\n", __func__);
|
||||
#endif
|
||||
break;
|
||||
telem_debug("oops_processed detected !\n");
|
||||
break;
|
||||
}
|
||||
linelength = 0;
|
||||
}
|
||||
@@ -128,7 +132,8 @@ void klog_process_oops_msgs(struct oops_log_msg *msg)
|
||||
//Add the newline character to the end of each line
|
||||
line = msg->lines[i];
|
||||
linelength = strlen(line);
|
||||
strncpy(bp, line, linelength);
|
||||
// Copy the line (without the terminating NULL)
|
||||
memcpy(bp, line, linelength);
|
||||
bp[linelength] = '\n';
|
||||
done += linelength + 1;
|
||||
bp = contents + done;
|
||||
@@ -136,16 +141,14 @@ void klog_process_oops_msgs(struct oops_log_msg *msg)
|
||||
|
||||
struct oops_log_msg oops_msg;
|
||||
if (handle_entire_oops(contents, (long)size, &oops_msg)) {
|
||||
#ifdef DEBUG
|
||||
printf("Raw message:\n");
|
||||
#ifdef DEBUG
|
||||
telem_debug("DEBUG: Raw oops message:\n");
|
||||
for (int i = 0; i < oops_msg.length; i++) {
|
||||
printf("%s\n", oops_msg.lines[i]);
|
||||
telem_log(LOG_DEBUG, "%s\n", oops_msg.lines[i]);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
payload = parse_payload(&oops_msg);
|
||||
#ifdef DEBUG
|
||||
printf("Payload Parsed :%s\n", payload->str);
|
||||
#endif
|
||||
telem_debug("DEBUG: Payload Parsed :%s\n", payload->str);
|
||||
oops_msg_cleanup(&oops_msg);
|
||||
send_data(payload->str, (char *)oops_msg.pattern->classification, (uint32_t)oops_msg.pattern->severity);
|
||||
nc_string_free(payload);
|
||||
|
||||
+20
-22
@@ -4,28 +4,21 @@ bin_PROGRAMS += \
|
||||
%D%/telem-record-gen \
|
||||
%D%/klogscanner \
|
||||
%D%/pstoreprobe \
|
||||
%D%/pythonprobe \
|
||||
%D%/pstoreclean \
|
||||
%D%/bertprobe
|
||||
|
||||
%C%_pythonprobe_SOURCES = %D%/python-probe.c
|
||||
%C%_pythonprobe_LDADD = $(top_builddir)/src/libtelemetry.la
|
||||
%C%_pythonprobe_LDFLAGS = \
|
||||
$(AM_LDFLAGS) \
|
||||
-pie
|
||||
%D%/pstoreclean
|
||||
|
||||
%C%_hprobe_SOURCES = %D%/hello.c
|
||||
%C%_hprobe_LDADD = $(top_builddir)/src/libtelemetry.la
|
||||
%C%_hprobe_CFLAGS = $(AM_CFLAGS)
|
||||
%C%_hprobe_LDFLAGS = \
|
||||
$(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
|
||||
if LOG_SYSTEMD
|
||||
if HAVE_SYSTEMD_JOURNAL
|
||||
%C%_hprobe_CFLAGS += $(SYSTEMD_JOURNAL_CFLAGS)
|
||||
%C%_hprobe_LDADD += $(SYSTEMD_JOURNAL_LIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
%C%_telem_record_gen_SOURCES = %D%/telem_record_gen.c
|
||||
%C%_telem_record_gen_CFLAGS = \
|
||||
@@ -35,6 +28,14 @@ bin_PROGRAMS += \
|
||||
$(AM_LDFLAGS) \
|
||||
-pie
|
||||
|
||||
if LOG_SYSTEMD
|
||||
if HAVE_SYSTEMD_JOURNAL
|
||||
%C%_telem_record_gen_CFLAGS += $(SYSTEMD_JOURNAL_CFLAGS)
|
||||
%C%_telem_record_gen_LDADD += $(SYSTEMD_JOURNAL_LIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
%C%_pstoreclean_SOURCES = %D%/pstore_clean.c
|
||||
%C%_pstoreclean_CFLAGS = \
|
||||
$(AM_CFLAGS)
|
||||
@@ -113,13 +114,6 @@ endif
|
||||
-pie
|
||||
|
||||
if LOG_SYSTEMD
|
||||
if HAVE_SYSTEMD_JOURNAL
|
||||
%C%_klogscanner_CFLAGS += \
|
||||
$(SYSTEMD_JOURNAL_CFLAGS)
|
||||
%C%_klogscanner_LDADD += \
|
||||
$(SYSTEMD_JOURNAL_LIBS)
|
||||
endif
|
||||
|
||||
if HAVE_SYSTEMD_JOURNAL
|
||||
%C%_klogscanner_CFLAGS += \
|
||||
$(SYSTEMD_JOURNAL_CFLAGS)
|
||||
@@ -149,6 +143,10 @@ bin_PROGRAMS += \
|
||||
%C%_journalprobe_LDFLAGS = \
|
||||
$(AM_LDFLAGS) \
|
||||
-pie
|
||||
if LOG_SYSTEMD
|
||||
%C%_journalprobe_CFLAGS += $(SYSTEMD_JOURNAL_CFLAGS)
|
||||
%C%_journalprobe_LDADD += $(SYSTEMD_JOURNAL_LIBS)
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
+63
-12
@@ -150,6 +150,24 @@ struct oops_pattern oops_patterns_arr[] = {
|
||||
TM_MEDIUM,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"ACPI Error:",
|
||||
"org.clearlinux/kernel/warning",
|
||||
TM_MEDIUM,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Kernel panic - not syncing:",
|
||||
"org.clearlinux/kernel/panic",
|
||||
TM_CRITICAL,
|
||||
false,
|
||||
},
|
||||
{
|
||||
"BERT: Error records from previous boot:",
|
||||
"org.clearlinux/bert/debug",
|
||||
TM_MEDIUM,
|
||||
false,
|
||||
},
|
||||
};
|
||||
|
||||
static int oops_patterns_cnt = sizeof(oops_patterns_arr) / sizeof(struct oops_pattern);
|
||||
@@ -322,6 +340,7 @@ void oops_msg_cleanup(struct oops_log_msg *msg)
|
||||
static struct oops_log_msg oops_msg;
|
||||
|
||||
static bool in_stack_dump = false;
|
||||
static bool in_bert_dump = false;
|
||||
|
||||
static oops_handler_t oops_handler;
|
||||
|
||||
@@ -345,6 +364,19 @@ void oops_parser_cleanup()
|
||||
free_pattern_regex();
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
[ 1.609112] BERT: Error records from previous boot:
|
||||
[ 1.609113] [Hardware Error]: event severity: fatal
|
||||
[ 1.609115] [Hardware Error]: Error 0, type: fatal
|
||||
[ 1.609116] [Hardware Error]: section type: unknown, 81212a96-09ed-4996-9471-8d729c8e69ed
|
||||
[ 1.609117] [Hardware Error]: section length: 0xc10
|
||||
[ 1.609119] [Hardware Error]: 00000000: 00000001 00000000 00000000 01001002 ................
|
||||
[ 1.609120] [Hardware Error]: 00000010: 01001002 00000001 c71f0d2f 00000003 ......../.......
|
||||
[ 1.609122] [Hardware Error]: 00000020: 00000001 0000004f 0c070048 800001ff ....O...H.......
|
||||
[ 1.609123] [Hardware Error]: 00000030: 02002080 7e15fe03 00000001 00000000 . .....~......
|
||||
...
|
||||
*/
|
||||
void parse_single_line(char *line, size_t size)
|
||||
{
|
||||
char *start;
|
||||
@@ -364,28 +396,30 @@ void parse_single_line(char *line, size_t size)
|
||||
continue;
|
||||
}
|
||||
telem_log(LOG_DEBUG, "Oops start has been detected\n");
|
||||
|
||||
oops_msg.pattern = pattern;
|
||||
oops_msg.lines[oops_msg.length] = strndup(start, (size_t)(line_end - start));
|
||||
if (oops_msg.lines[oops_msg.length] == NULL) {
|
||||
//telem_perror("Failed to copy string");
|
||||
exit(EXIT_FAILURE);
|
||||
return;
|
||||
} else {
|
||||
oops_msg.length++;
|
||||
}
|
||||
|
||||
oops_msg.length++;
|
||||
in_stack_dump = false;
|
||||
break;
|
||||
in_bert_dump = false;
|
||||
if (strstr(oops_msg.pattern->begin_line, "BERT:")) {
|
||||
in_bert_dump = true;
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
// If in the middle of oops
|
||||
if (oops_msg.length >= MAX_LINES) {
|
||||
fprintf(stderr,"*** MAX_LINES!!\n");
|
||||
end_found = true;
|
||||
// } else if (oops_msg.end_line && strstr(start, oops_msg.end_line)) {
|
||||
// end_found = false;
|
||||
} else if (strstr(start, "[ end trace")) {
|
||||
end_found = true;
|
||||
} else if (!in_stack_dump) {
|
||||
} else if (!in_stack_dump && !in_bert_dump) {
|
||||
// This line indicates the beginning of a stack trace;
|
||||
// the next line is most likely the topmost frame.
|
||||
if (starts_with(start, line_end, "Call Trace:")) {
|
||||
@@ -402,6 +436,10 @@ void parse_single_line(char *line, size_t size)
|
||||
in_stack_dump = false;
|
||||
end_found = true;
|
||||
}
|
||||
} else if (in_bert_dump) {
|
||||
if (!strstr(start, "[Hardware Error]:")) {
|
||||
end_found = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* if a new oops starts, this one has ended */
|
||||
@@ -469,7 +507,7 @@ static void stack_frame_append(struct stack_frame **head, struct stack_frame **t
|
||||
while (*start && !isspace(*start)) {
|
||||
start++;
|
||||
}
|
||||
if (start && *start == '\0') {
|
||||
if (*start == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -504,7 +542,7 @@ static void stack_frame_append(struct stack_frame **head, struct stack_frame **t
|
||||
while (*start && !isspace(*start)) {
|
||||
start++;
|
||||
}
|
||||
if (start && *start == '\0') {
|
||||
if (*start == '\0') {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -835,15 +873,28 @@ static nc_string *parse_backtrace(struct oops_log_msg *msg)
|
||||
return backtrace;
|
||||
}
|
||||
|
||||
static void append_payload(nc_string *payload, struct oops_log_msg *msg)
|
||||
{
|
||||
for (int i = 1; i < msg->length; i++) {
|
||||
nc_string_cat(payload,msg->lines[i]);
|
||||
nc_string_cat(payload,"\n");
|
||||
}
|
||||
}
|
||||
|
||||
nc_string *parse_payload(struct oops_log_msg *msg)
|
||||
{
|
||||
nc_string *payload, *backtrace;
|
||||
|
||||
payload = nc_string_dup("Crash Report:\n");
|
||||
nc_string_append_printf(payload, "Reason: %s\n", msg->lines[0]);
|
||||
backtrace = parse_backtrace(msg);
|
||||
nc_string_cat(payload, backtrace->str);
|
||||
nc_string_free(backtrace);
|
||||
if (strstr(msg->lines[0], "BERT:")) {
|
||||
append_payload(payload, msg);
|
||||
} else {
|
||||
backtrace = parse_backtrace(msg);
|
||||
nc_string_cat(payload, backtrace->str);
|
||||
nc_string_free(backtrace);
|
||||
}
|
||||
|
||||
return payload;
|
||||
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ int main(int argc, char **argv)
|
||||
if (mkdir(MOUNT, 0755) < 0) {
|
||||
//If there is an error other than an existing directory
|
||||
if (errno != EEXIST) {
|
||||
telem_log(LOG_ERR, "Error creating directory /dev/pstore : %s\n", strerror(errno));
|
||||
telem_perror("Error creating directory /dev/pstore");
|
||||
//bail out?
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
+44
-10
@@ -15,6 +15,7 @@
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <dirent.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
@@ -65,14 +66,12 @@ void handle_complete_oops_message(struct oops_log_msg *msg)
|
||||
|
||||
#ifdef DEBUG
|
||||
for (int i = 0; i < msg->length; i++) {
|
||||
printf("%s\n", msg->lines[i]);
|
||||
telem_debug("DEBUG: %s\n", msg->lines[i]);
|
||||
}
|
||||
#endif
|
||||
payload = parse_payload(msg);
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("Payload Parsed :%s\n", payload->str);
|
||||
#endif
|
||||
telem_debug("DEBUG: Payload Parsed :%s\n", payload->str);
|
||||
send_data(payload->str, (char *)msg->pattern->classification, (uint32_t)msg->pattern->severity);
|
||||
nc_string_free(payload);
|
||||
}
|
||||
@@ -197,6 +196,13 @@ struct chunk_list {
|
||||
struct chunk_list *next;
|
||||
};
|
||||
|
||||
static void print_usage(char *prog)
|
||||
{
|
||||
printf("%s: Usage\n", prog);
|
||||
printf(" -f, --config_file This overides the other parameters\n");
|
||||
printf(" -h, --help Display this help message\n");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
DIR *pstore_dir;
|
||||
@@ -207,6 +213,32 @@ int main(int argc, char **argv)
|
||||
int max_part;
|
||||
size_t totalsize = 0;
|
||||
char *crash_dump = NULL;
|
||||
int c;
|
||||
int opt_index = 0;
|
||||
|
||||
struct option opts[] = {
|
||||
{ "config_file", 1, NULL, 'f' },
|
||||
{ "help", 0, NULL, 'h' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
while ((c = getopt_long(argc, argv, "f:h", opts, &opt_index)) != -1) {
|
||||
switch (c) {
|
||||
case 'f':
|
||||
if (tm_set_config_file(optarg) != 0) {
|
||||
telem_log(LOG_ERR, "Configuration file"
|
||||
" path not valid\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
case '?':
|
||||
print_usage(argv[0]);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Hash table used to store chunks belonging to a oops counter
|
||||
@@ -232,9 +264,13 @@ int main(int argc, char **argv)
|
||||
// Look for only dmesg logs. Ignore other types of pstore dumps for now.
|
||||
if (sscanf(entry->d_name, "dmesg-efi-%" PRIu64, &id) == 1) {
|
||||
parse_id(id, &count, &part);
|
||||
#ifdef DEBUG
|
||||
printf("Extracted count :%d, part : %d\n", count, part);
|
||||
#endif
|
||||
telem_debug("dmesg-efi Extracted count :%d, part : %d\n",
|
||||
count, part);
|
||||
} else if (sscanf(entry->d_name, "dmesg-ramoops-%" PRIu64, &id) == 1) {
|
||||
count = (int)(id + 1);
|
||||
part = 1;
|
||||
telem_debug("dmesg-ramoops Extracted count :%d, part : %d\n",
|
||||
count, part);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
@@ -262,9 +298,7 @@ int main(int argc, char **argv)
|
||||
|
||||
nc_hashmap_iter_init(hash, &iter);
|
||||
while (nc_hashmap_iter_next(&iter, (void **)&key, (void **)&value)) {
|
||||
#ifdef DEBUG
|
||||
printf("Count in the hash: %d\n", NC_UNHASH_KEY(key));
|
||||
#endif
|
||||
telem_debug("DEBUG: Count in the hash: %d\n", NC_UNHASH_KEY(key));
|
||||
|
||||
head = (struct chunk_list *)value;
|
||||
elem = head;
|
||||
|
||||
@@ -1,293 +0,0 @@
|
||||
/*
|
||||
* This program is part of the Clear Linux Project
|
||||
*
|
||||
* Copyright 2019 Intel Corporation
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/inotify.h>
|
||||
#include <fcntl.h>
|
||||
#include <dirent.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <getopt.h>
|
||||
|
||||
#include "log.h"
|
||||
#include "telemetry.h"
|
||||
|
||||
#define PYTHON_TELEMETRY_DIR "/var/lib/telemetry/python"
|
||||
|
||||
/* We expect something like: 1.python-exception.3.N2Qy24 */
|
||||
static bool validate_file_name(const char *filename, uint32_t *severity,
|
||||
char** class, uint32_t *version)
|
||||
{
|
||||
unsigned int ver, sev;
|
||||
char cls[PATH_MAX] = { 0 };
|
||||
char rnd[PATH_MAX] = { 0 };
|
||||
char *filename_base = basename(filename);
|
||||
char *str_class = NULL;
|
||||
|
||||
if (!filename_base) {
|
||||
telem_perror("basename failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sscanf(filename_base,"%u.%[^]0-9.].%u.%s", &ver, cls, &sev, rnd) == 4) {
|
||||
if (asprintf(&str_class, "org.clearlinux/python/%s", cls) < 29) {
|
||||
telem_log(LOG_ERR, "%s: invalid telemetry classification\n",
|
||||
str_class);
|
||||
return false;
|
||||
}
|
||||
*class = str_class;
|
||||
*version = ver;
|
||||
*severity = sev;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static char *read_file_into_buffer(const char *filename)
|
||||
{
|
||||
FILE *fp = NULL;
|
||||
char *contents = NULL;
|
||||
long sz;
|
||||
size_t size, bytes_read;
|
||||
|
||||
fp = fopen(filename, "r");
|
||||
if (fp == NULL) {
|
||||
telem_log(LOG_ERR, "Failed to open Python telemetry file %s: %s\n",
|
||||
filename, strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (fseek(fp, 0, SEEK_END) == -1) {
|
||||
telem_log(LOG_ERR, "Failed to seek file %s: %s\n", filename,
|
||||
strerror(errno));
|
||||
goto error_end;
|
||||
}
|
||||
|
||||
sz = ftell(fp);
|
||||
if (sz == -1L) {
|
||||
telem_perror("ftell failed");
|
||||
goto error_end;
|
||||
}
|
||||
|
||||
if (sz == 0L) {
|
||||
telem_perror("File is empty\n");
|
||||
goto error_end;
|
||||
}
|
||||
|
||||
if (fseek(fp, 0, SEEK_SET) < 0) {
|
||||
telem_log(LOG_ERR, "fseek failed for file %s:%s\n", filename,
|
||||
strerror(errno));
|
||||
goto error_end;
|
||||
}
|
||||
|
||||
size = (size_t)sz;
|
||||
contents = calloc(sizeof(char), size);
|
||||
if (!contents) {
|
||||
telem_log(LOG_ERR, "Call to calloc failed\n");
|
||||
goto error_end;
|
||||
}
|
||||
|
||||
bytes_read = fread(contents, sizeof(char), size, fp);
|
||||
|
||||
if (bytes_read < size) {
|
||||
telem_log(LOG_ERR, "Error while reading file %s:%s\n", filename,
|
||||
strerror(errno));
|
||||
goto error_end;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return contents;
|
||||
|
||||
error_end:
|
||||
fclose(fp);
|
||||
if (contents) {
|
||||
free(contents);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void send_data(char *contents, uint32_t severity, char *class,
|
||||
uint32_t version)
|
||||
{
|
||||
struct telem_ref *handle = NULL;
|
||||
int ret;
|
||||
|
||||
if ((ret = tm_create_record(&handle, severity, class, version)) < 0) {
|
||||
telem_log(LOG_ERR, "Failed to create record: %s\n",
|
||||
strerror(-ret));
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ret = tm_set_payload(handle, contents)) < 0) {
|
||||
telem_log(LOG_ERR, "Failed to set payload: %s\n",
|
||||
strerror(-ret));
|
||||
tm_free_record(handle);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((ret = tm_send_record(handle)) < 0) {
|
||||
telem_log(LOG_ERR, "Failed to send record: %s\n",
|
||||
strerror(-ret));
|
||||
}
|
||||
|
||||
tm_free_record(handle);
|
||||
}
|
||||
|
||||
/* Send a valid file to the backend. */
|
||||
static void deliver_payload(const char *filename)
|
||||
{
|
||||
uint32_t severity;
|
||||
uint32_t version;
|
||||
char *class = NULL;
|
||||
char *contents = NULL;
|
||||
|
||||
if (validate_file_name(filename, &severity, &class, &version)) {
|
||||
if ((contents = read_file_into_buffer(filename)) != NULL) {
|
||||
send_data(contents, severity, class, version);
|
||||
free(contents);
|
||||
}
|
||||
|
||||
free(class);
|
||||
}
|
||||
|
||||
/* Keep PYTHON_TELEMETRY_DIR empty. Delete the file. */
|
||||
if (unlink(filename) != 0) {
|
||||
telem_log(LOG_ERR, "Failed to unlink %s: %s\n", filename,
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static void drop_privs(void)
|
||||
{
|
||||
uid_t euid;
|
||||
|
||||
euid = geteuid();
|
||||
if (euid != 0) {
|
||||
telem_log(LOG_DEBUG, "Not root; skipping privilege drop\n");
|
||||
return;
|
||||
}
|
||||
|
||||
struct passwd *pw;
|
||||
|
||||
pw = getpwnam("telemetry");
|
||||
if (!pw) {
|
||||
telem_log(LOG_ERR, "telemetry user not found\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// The order is important here:
|
||||
// change supplemental groups, our gid, and then our uid
|
||||
if (initgroups(pw->pw_name, pw->pw_gid) != 0) {
|
||||
telem_perror("Failed to set supplemental group list");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (setgid(pw->pw_gid) != 0) {
|
||||
telem_perror("Failed to set GID");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (setuid(pw->pw_uid) != 0) {
|
||||
telem_perror("Failed to set UID");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
assert(getuid() == pw->pw_uid);
|
||||
assert(geteuid() == pw->pw_uid);
|
||||
assert(getgid() == pw->pw_gid);
|
||||
assert(getegid() == pw->pw_gid);
|
||||
}
|
||||
|
||||
static 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");
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
int c;
|
||||
int opt_index = 0;
|
||||
|
||||
struct option opts[] = {
|
||||
{ "config_file", 1, NULL, 'f' },
|
||||
{ "help", 0, NULL, 'h' },
|
||||
{ "version", 0, NULL, 'V' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
drop_privs();
|
||||
|
||||
while ((c = getopt_long(argc, argv, "f:hV", opts, &opt_index)) != -1) {
|
||||
switch (c) {
|
||||
case 'f':
|
||||
if (tm_set_config_file(optarg) != 0) {
|
||||
telem_log(LOG_ERR, "Configuration file"
|
||||
" path not valid\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
print_usage(argv[0]);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'V':
|
||||
printf(PACKAGE_VERSION "\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
case '?':
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (chdir(PYTHON_TELEMETRY_DIR)) {
|
||||
perror(PYTHON_TELEMETRY_DIR);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* Process all existing files */
|
||||
dir = opendir(PYTHON_TELEMETRY_DIR);
|
||||
if (!dir) {
|
||||
perror(PYTHON_TELEMETRY_DIR);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
entry = readdir(dir);
|
||||
if (!entry) {
|
||||
break;
|
||||
}
|
||||
if (entry->d_name[0] == '.') {
|
||||
continue;
|
||||
}
|
||||
deliver_payload(entry->d_name);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This program is part of the Clear Linux Project
|
||||
*
|
||||
* Copyright 2015 Intel Corporation
|
||||
* Copyright 2019 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
|
||||
@@ -32,7 +32,6 @@
|
||||
#include "common.h"
|
||||
#include "telemetry.h"
|
||||
|
||||
static char *config_file = NULL;
|
||||
static uint32_t severity = 1;
|
||||
static char *opt_class = NULL;
|
||||
static char *opt_payload = NULL;
|
||||
@@ -53,6 +52,7 @@ static const struct option prog_opts[] = {
|
||||
{ "payload-file", required_argument, 0, 'P' },
|
||||
{ "record-version", required_argument, 0, 'R' },
|
||||
{ "event-id", required_argument, 0, 'e' },
|
||||
{ "config-file", required_argument, 0, 'f' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
@@ -74,31 +74,18 @@ static void print_help(void)
|
||||
printf(" -e, --event-id Event id to use in the record\n");
|
||||
printf(" -o, --echo Echo record to stdout\n");
|
||||
printf(" -n, --no-post Do not post record just print\n");
|
||||
printf(" -f, --config_file Specify a configuration file other than default\n");
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
const unsigned int count_chars(const char *check, const char character)
|
||||
static bool parse_options(int argc, char **argv)
|
||||
{
|
||||
unsigned int count = 0U;
|
||||
if (check == NULL) {
|
||||
return count;
|
||||
}
|
||||
for (; *check != '\0'; ++check) {
|
||||
if (*check == character) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
int parse_options(int argc, char **argv)
|
||||
{
|
||||
int ret = 0;
|
||||
bool ret = false;
|
||||
char *endptr = NULL;
|
||||
long unsigned int tmp = 0;
|
||||
|
||||
int opt;
|
||||
while ((opt = getopt_long(argc, argv, "hc:Vs:c:p:P:R:e:on", prog_opts, NULL)) != -1) {
|
||||
while ((opt = getopt_long(argc, argv, "hc:Vs:c:p:P:R:e:onf:", prog_opts, NULL)) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
print_help();
|
||||
@@ -123,12 +110,21 @@ int parse_options(int argc, char **argv)
|
||||
severity = (uint32_t)tmp;
|
||||
break;
|
||||
case 'c':
|
||||
if (opt_class != NULL) {
|
||||
free(opt_class);
|
||||
}
|
||||
opt_class = strdup(optarg);
|
||||
break;
|
||||
case 'p':
|
||||
if (opt_payload != NULL) {
|
||||
free(opt_payload);
|
||||
}
|
||||
opt_payload = strdup(optarg);
|
||||
break;
|
||||
case 'P':
|
||||
if (opt_payload_file != NULL) {
|
||||
free(opt_payload_file);
|
||||
}
|
||||
opt_payload_file = strdup(optarg);
|
||||
break;
|
||||
case 'R':
|
||||
@@ -148,6 +144,9 @@ int parse_options(int argc, char **argv)
|
||||
payload_version = (uint32_t)tmp;
|
||||
break;
|
||||
case 'e':
|
||||
if (opt_event_id != NULL) {
|
||||
free(opt_event_id);
|
||||
}
|
||||
opt_event_id = strdup(optarg);
|
||||
if (opt_event_id == NULL) {
|
||||
goto fail;
|
||||
@@ -159,31 +158,38 @@ int parse_options(int argc, char **argv)
|
||||
case 'n':
|
||||
opt_nopost = true;
|
||||
break;
|
||||
case 'f':
|
||||
if (tm_set_config_file(optarg) != 0) {
|
||||
telem_log(LOG_ERR, "Configuration file path not valid\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
ret = true;
|
||||
fail:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int validate_opts(void)
|
||||
static bool validate_opts(void)
|
||||
{
|
||||
size_t len;
|
||||
int ret = 0;
|
||||
size_t i, len;
|
||||
int x, slashes = 0;
|
||||
const char alphab[] = EVENT_ID_ALPHAB;
|
||||
bool ret = false;
|
||||
|
||||
/* classification */
|
||||
if (opt_class == NULL) {
|
||||
fprintf(stderr, "Error: Classification required. See --help.\n");
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
len = strlen(opt_class);
|
||||
|
||||
if ((len == 0) || (len > 120)) {
|
||||
if ((len == 0) || (len > MAX_CLASS_LENGTH)) {
|
||||
fprintf(stderr, "Error: Valid size for classification "
|
||||
"is 1-120 chars\n");
|
||||
"is 1-%d chars\n", MAX_CLASS_LENGTH);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -195,12 +201,27 @@ int validate_opts(void)
|
||||
}
|
||||
}
|
||||
|
||||
if (count_chars(opt_class, '/') != 2) {
|
||||
for (i = 0, x = 0; i <= (len - 1); i++, x++) {
|
||||
if (opt_class[i] == '/') {
|
||||
slashes++;
|
||||
x = 0;
|
||||
} else {
|
||||
if (x > MAX_SUBCAT_LENGTH) {
|
||||
fprintf(stderr, "Error: Classification strings"
|
||||
" between slashes should have at most"
|
||||
" %d chars\n", MAX_SUBCAT_LENGTH);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (slashes != 2) {
|
||||
fprintf(stderr, "Error: Classification needs to be in "
|
||||
"most/to/least specific format, 2 \'/\' required.\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Severity */
|
||||
if ((severity) < 1 || (severity > 4)) {
|
||||
fprintf(stderr, "Error: Valid range for severity is 1-4\n");
|
||||
@@ -221,29 +242,12 @@ int validate_opts(void)
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
int allocate_payload_buffer(char **payload)
|
||||
static bool get_payload_from_file(char **payload)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
*payload = (char *)malloc(MAX_PAYLOAD_LENGTH);
|
||||
|
||||
if (*payload == NULL) {
|
||||
goto out1;
|
||||
}
|
||||
|
||||
*payload = memset(*payload, 0, MAX_PAYLOAD_LENGTH);
|
||||
ret = 1;
|
||||
|
||||
out1:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int get_payload_from_file(char **payload)
|
||||
{
|
||||
int ret = 1;
|
||||
bool ret = false;
|
||||
FILE *fp = NULL;
|
||||
size_t bytes_in = 0;
|
||||
|
||||
@@ -260,10 +264,10 @@ int get_payload_from_file(char **payload)
|
||||
|
||||
/* if fread fails */
|
||||
if (bytes_in == 0 && ferror(fp) != 0) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = true;
|
||||
out:
|
||||
if (fp) {
|
||||
fclose(fp);
|
||||
@@ -272,7 +276,7 @@ out:
|
||||
|
||||
}
|
||||
|
||||
void get_payload_from_opt(char **payload)
|
||||
static void get_payload_from_opt(char **payload)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
@@ -280,10 +284,12 @@ void get_payload_from_opt(char **payload)
|
||||
if (len >= MAX_PAYLOAD_LENGTH) {
|
||||
len = MAX_PAYLOAD_LENGTH - 1;
|
||||
}
|
||||
strncpy(*payload, opt_payload, len);
|
||||
|
||||
/* "payload" is pre-allocated zeroed buffer of MAX_PAYLOAD_LENGTH */
|
||||
memcpy(*payload, opt_payload, len);
|
||||
}
|
||||
|
||||
void get_payload_from_stdin(char **payload)
|
||||
static void get_payload_from_stdin(char **payload)
|
||||
{
|
||||
size_t bytes_in = 0;
|
||||
int c;
|
||||
@@ -299,40 +305,40 @@ void get_payload_from_stdin(char **payload)
|
||||
|
||||
}
|
||||
|
||||
int get_payload(char **payload)
|
||||
static bool get_payload(char **payload)
|
||||
{
|
||||
int ret = 0;
|
||||
bool ret = false;
|
||||
|
||||
if (!allocate_payload_buffer(payload)) {
|
||||
goto out1;
|
||||
}
|
||||
*payload = (char *)calloc(sizeof(char), MAX_PAYLOAD_LENGTH);
|
||||
|
||||
if (*payload == NULL)
|
||||
return false;
|
||||
|
||||
if (opt_payload_file) {
|
||||
|
||||
if (get_payload_from_file(payload)) {
|
||||
ret = 1;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
} else if (opt_payload) {
|
||||
|
||||
get_payload_from_opt(payload);
|
||||
ret = 1;
|
||||
ret = true;
|
||||
|
||||
} else {
|
||||
get_payload_from_stdin(payload);
|
||||
ret = 1;
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (ret == 0) {
|
||||
if (ret == false) {
|
||||
free(*payload);
|
||||
*payload = NULL;
|
||||
}
|
||||
|
||||
out1:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int instanciate_record(struct telem_ref **t_ref, char *payload)
|
||||
static int instanciate_record(struct telem_ref **t_ref, char *payload)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
@@ -341,18 +347,18 @@ int instanciate_record(struct telem_ref **t_ref, char *payload)
|
||||
goto out1;
|
||||
}
|
||||
|
||||
if ((ret = opt_event_id && tm_set_event_id(*t_ref, opt_event_id)) < 0) {
|
||||
goto out1;
|
||||
if (opt_event_id) {
|
||||
if ((ret = tm_set_event_id(*t_ref, opt_event_id)) < 0) {
|
||||
goto out1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((ret = tm_set_payload(*t_ref, payload)) < 0) {
|
||||
goto out1;
|
||||
}
|
||||
ret = tm_set_payload(*t_ref, payload);
|
||||
out1:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int send_record(char *payload)
|
||||
static int send_record(char *payload)
|
||||
{
|
||||
struct telem_ref *t_ref = NULL;
|
||||
int ret = 0;
|
||||
@@ -362,6 +368,9 @@ int send_record(char *payload)
|
||||
}
|
||||
|
||||
if ((ret = tm_send_record(t_ref)) < 0) {
|
||||
if (ret == -ECONNREFUSED) {
|
||||
fprintf(stderr, "Unable to send record. Make sure to opt-in to telemetry first 'telemctl opt-in'\n");
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -371,20 +380,20 @@ out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int print_record(char *payload)
|
||||
static int print_record(char *payload)
|
||||
{
|
||||
struct telem_ref *t_ref = NULL;
|
||||
int ret = 0;
|
||||
int i = 0;
|
||||
int ret;
|
||||
|
||||
if ((ret = instanciate_record(&t_ref, payload)) == 0) {
|
||||
int i;
|
||||
for (i = 0; i < NUM_HEADERS; i++) {
|
||||
fprintf(stdout, "%s", t_ref->record->headers[i]);
|
||||
}
|
||||
fprintf(stdout, "%s\n", t_ref->record->payload);
|
||||
tm_free_record(t_ref);
|
||||
}
|
||||
|
||||
tm_free_record(t_ref);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -415,7 +424,6 @@ int main(int argc, char **argv)
|
||||
|
||||
ret = EXIT_SUCCESS;
|
||||
fail:
|
||||
free(config_file);
|
||||
free(opt_class);
|
||||
free(opt_payload);
|
||||
free(opt_event_id);
|
||||
|
||||
+52
-12
@@ -202,9 +202,15 @@ void transmit_spooled_record(char *record_path, bool *post_succeeded, long size)
|
||||
FILE *fp = NULL;
|
||||
char *headers[NUM_HEADERS];
|
||||
char *payload = NULL;
|
||||
int i, k;
|
||||
char line[LINE_MAX] = { 0 };
|
||||
int num_headers = 0, k;
|
||||
#if (LINE_MAX > PATH_MAX)
|
||||
char line[LINE_MAX+1] = { 0 };
|
||||
#else
|
||||
char line[PATH_MAX+1] = { 0 };
|
||||
#endif
|
||||
long offset;
|
||||
char *cfg_file = NULL;
|
||||
uint32_t cfg_prefix = 0;
|
||||
|
||||
fp = fopen(record_path, "r");
|
||||
if (fp == NULL) {
|
||||
@@ -212,16 +218,47 @@ void transmit_spooled_record(char *record_path, bool *post_succeeded, long size)
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < NUM_HEADERS; i++) {
|
||||
const char *header_name = get_header_name(i);
|
||||
if (!fgets(line, LINE_MAX, fp)) {
|
||||
// First line optionally contains configuration file path
|
||||
if (fread(&cfg_prefix, CFG_PREFIX_LENGTH, 1, fp) != 1) {
|
||||
telem_log(LOG_ERR, "Error while parsing spooled record configuration info.\n");
|
||||
goto read_error;
|
||||
}
|
||||
|
||||
if (cfg_prefix == CFG_PREFIX_32BIT) {
|
||||
size_t pathlen;
|
||||
char *nl;
|
||||
|
||||
if (!fgets(line, sizeof(line), fp)) {
|
||||
telem_log(LOG_ERR, "Error while parsing record file\n");
|
||||
fclose(fp);
|
||||
return;
|
||||
goto read_error;
|
||||
}
|
||||
|
||||
if ((nl = strchr(line, '\n')) != NULL) {
|
||||
*nl = '\0';
|
||||
}
|
||||
|
||||
pathlen = strlen(line);
|
||||
cfg_file = malloc(pathlen + 1);
|
||||
if (cfg_file == NULL) {
|
||||
telem_log(LOG_ERR, "Could not allocate memory for config file path\n");
|
||||
goto read_error;
|
||||
}
|
||||
strcpy (cfg_file, line);
|
||||
telem_debug("DEBUG: cfg_file: %s\n", cfg_file);
|
||||
} else {
|
||||
cfg_file = NULL;
|
||||
rewind(fp);
|
||||
}
|
||||
|
||||
for (num_headers = 0; num_headers < NUM_HEADERS; num_headers++) {
|
||||
const char *header_name = get_header_name(num_headers);
|
||||
if (!fgets(line, sizeof(line), fp)) {
|
||||
telem_log(LOG_ERR, "Error while parsing record file\n");
|
||||
goto read_error;
|
||||
}
|
||||
//Get rid of trailing newline
|
||||
strtok(line, "\n");
|
||||
if (get_header(line, header_name, &headers[i])) {
|
||||
if (get_header(line, header_name, &headers[num_headers])) {
|
||||
continue;
|
||||
} else {
|
||||
telem_log(LOG_ERR, "transmit_spooled_record: Incorrect"
|
||||
@@ -242,8 +279,7 @@ void transmit_spooled_record(char *record_path, bool *post_succeeded, long size)
|
||||
|
||||
if (!payload) {
|
||||
telem_log(LOG_ERR, "Could not allocate memory for payload\n");
|
||||
fclose(fp);
|
||||
return;
|
||||
goto read_error;
|
||||
}
|
||||
memset(payload, 0, (size_t)size);
|
||||
|
||||
@@ -254,7 +290,7 @@ void transmit_spooled_record(char *record_path, bool *post_succeeded, long size)
|
||||
goto read_error;
|
||||
}
|
||||
|
||||
*post_succeeded = post_record_http(headers, payload);
|
||||
*post_succeeded = post_record_http(headers, payload, cfg_file);
|
||||
if (*post_succeeded) {
|
||||
unlink(record_path);
|
||||
}
|
||||
@@ -267,9 +303,13 @@ read_error:
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
for (k = 0; k < i; k++) {
|
||||
for (k = 0; k < num_headers; k++) {
|
||||
free(headers[k]);
|
||||
}
|
||||
|
||||
if (cfg_file) {
|
||||
free(cfg_file);
|
||||
}
|
||||
}
|
||||
|
||||
int spool_record_compare(const void *entrya, const void *entryb, void *path)
|
||||
|
||||
+555
@@ -0,0 +1,555 @@
|
||||
/*
|
||||
* This program is part of the Clear Linux Project
|
||||
*
|
||||
* Copyright 2019 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 <stdbool.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <ftw.h>
|
||||
#include <unistd.h>
|
||||
#include <locale.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
#include <errno.h>
|
||||
|
||||
#define TELEM_DIR "/etc/telemetrics"
|
||||
#define TM_OPT_IN TELEM_DIR"/opt-in"
|
||||
|
||||
#define TELEM_WRK_DIRS_CONF "/usr/lib/tmpfiles.d/telemetrics-dirs.conf"
|
||||
|
||||
#define cmd_create_tmp_files "systemd-tmpfiles --create " TELEM_WRK_DIRS_CONF
|
||||
#define cmd_mk_telemdir "mkdir -p " TELEM_DIR
|
||||
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||
|
||||
static char *SPECIAL_UNITS[] = {
|
||||
"hprobe.timer",
|
||||
"telemprobd.socket",
|
||||
"telempostd.path",
|
||||
"klogscanner.service",
|
||||
"journal-probe-tail.service",
|
||||
};
|
||||
|
||||
#define NUM_SPECIAL_UNITS ARRAY_SIZE(SPECIAL_UNITS)
|
||||
|
||||
static char *SERVICES[] = {
|
||||
"hprobe.service",
|
||||
"pstore-probe.service",
|
||||
"telemprobd.service",
|
||||
"telempostd.service",
|
||||
"journal-probe.service",
|
||||
};
|
||||
|
||||
#define NUM_SERVICES ARRAY_SIZE(SERVICES)
|
||||
|
||||
static int telemctl_start(void);
|
||||
static int telemctl_stop(void);
|
||||
static int telemctl_restart(void);
|
||||
static int telemctl_is_active(void);
|
||||
static int telemctl_opt_out(void);
|
||||
static int telemctl_opt_in(void);
|
||||
static int telemctl_journal(char *);
|
||||
|
||||
struct telemcmd {
|
||||
bool root;
|
||||
char *cmd;
|
||||
union {
|
||||
int (*f1)(void);
|
||||
int (*f2)(char *);
|
||||
} f;
|
||||
char *doc;
|
||||
};
|
||||
|
||||
static struct telemcmd commands[] = {
|
||||
{true, "stop", {.f1=telemctl_stop}, "Stops all running telemetry services" },
|
||||
{true, "start", {.f1=telemctl_start}, "Starts all telemetry services" },
|
||||
{true, "restart", {.f1=telemctl_restart}, "Restarts all telemetry services" },
|
||||
{false, "is-active", {.f1=telemctl_is_active},"Checks if telemprobd and telempostd are active" },
|
||||
{true, "opt-in", {.f1=telemctl_opt_in}, "Opts in to telemetry, and starts telemetry services" },
|
||||
{true, "opt-out", {.f1=telemctl_opt_out}, "Opts out of telemetry, and stops telemetry services" },
|
||||
{true, "journal", {.f2=telemctl_journal}, "Prints telemetry journal contents. Use -h argument with\n command for more options"}
|
||||
};
|
||||
|
||||
static int syscmd(char *cmd, char *buff, int bufflen)
|
||||
{
|
||||
int status;
|
||||
#ifdef DEBUG
|
||||
printf("[debug] [%s] %s\n", __func__, cmd);
|
||||
#endif
|
||||
FILE *fp = popen(cmd, "r");
|
||||
if (fp == NULL) {
|
||||
perror("popen");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (fgets(buff, bufflen, fp) != NULL) {
|
||||
;
|
||||
}
|
||||
|
||||
status = pclose(fp);
|
||||
if (status == -1) {
|
||||
perror("pclose");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/*
|
||||
Script code:
|
||||
|
||||
for_each_service() {
|
||||
local action=$1 && shift
|
||||
local -a array=($*)
|
||||
for service in "${array[@]}"; do
|
||||
systemctl $action $service
|
||||
[ $? -ne 0 ] && notice "Failed to $action ${service}. Continuing..."
|
||||
done
|
||||
}
|
||||
*/
|
||||
static int for_each_service(const char *command, char* services[], int numservices)
|
||||
{
|
||||
char buff[512];
|
||||
char cmd[256];
|
||||
int ret = 0, status;
|
||||
|
||||
for (int i = 0; i < numservices; i++) {
|
||||
snprintf(cmd, sizeof(cmd), "systemctl %s %s", command, services[i]);
|
||||
memset(buff, 0, sizeof(buff));
|
||||
status = syscmd(cmd, buff, sizeof(buff));
|
||||
if (status != 0 || buff[0] != 0) {
|
||||
fprintf(stderr, "%s", buff);
|
||||
fprintf(stderr, "Failed to %s %s. Continuing...", command, services[i]);
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
Script code:
|
||||
|
||||
telem_start() {
|
||||
[ -f $OPT_OUT_FILE ] && exit_err "Opt out is enabled. Cannot start services."
|
||||
create_work_dirs
|
||||
for_each_service "start" ${SPECIAL_UNITS[@]}
|
||||
}
|
||||
|
||||
Modified to add explicit opt-in
|
||||
*/
|
||||
static int telemctl_start(void)
|
||||
{
|
||||
char buff[512];
|
||||
int status, ret;
|
||||
|
||||
if (access(TM_OPT_IN, F_OK) != 0) {
|
||||
fprintf(stderr, "Opt in to telemetry first.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Creates dirs if missing, adjust ownership if exists */
|
||||
memset(buff, 0, sizeof(buff));
|
||||
|
||||
/* Execute "systemd-tmpfiles --create ${TELEM_WRK_DIRS_CONF}" */
|
||||
status = syscmd(cmd_create_tmp_files, buff, sizeof(buff));
|
||||
fprintf(stderr, "%s", buff);
|
||||
|
||||
if (status == -1) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = for_each_service("start", SPECIAL_UNITS, NUM_SPECIAL_UNITS);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Script code:
|
||||
|
||||
telem_stop() {
|
||||
for_each_service "stop" ${SPECIAL_UNITS[@]}
|
||||
for_each_service "stop" ${SERVICES[@]}
|
||||
}
|
||||
*/
|
||||
static int telemctl_stop(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* the special units must be stopped first so that activation no longer happens */
|
||||
ret = for_each_service("stop", SPECIAL_UNITS, NUM_SPECIAL_UNITS);
|
||||
ret |= for_each_service("stop", SERVICES, NUM_SERVICES);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
Script code:
|
||||
*
|
||||
telem_restart() {
|
||||
telem_stop
|
||||
telem_start
|
||||
}
|
||||
*/
|
||||
static int telemctl_restart(void)
|
||||
{
|
||||
if (telemctl_stop() == 0) {
|
||||
return telemctl_start();
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
Script code:
|
||||
|
||||
telem_is_active() {
|
||||
echo "telemprobd :" $(systemctl is-active telemprobd.socket)
|
||||
echo "telempostd :" $(systemctl is-active telempostd.path)
|
||||
}
|
||||
*/
|
||||
|
||||
static int telemctl_is_active(void)
|
||||
{
|
||||
char buff[256];
|
||||
|
||||
memset(buff, 0, sizeof(buff));
|
||||
if (syscmd("systemctl is-active telemprobd.socket", buff, sizeof(buff)) != -1) {
|
||||
printf("telemprobd : %s", buff);
|
||||
memset(buff, 0, sizeof(buff));
|
||||
if (syscmd("systemctl is-active telempostd.path",buff, sizeof(buff)) != -1) {
|
||||
printf("telempostd : %s", buff);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf)
|
||||
{
|
||||
int rv = remove(fpath);
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "[debug] [%s] remove fpath:%s rv:%d\n", __func__, fpath, rv);
|
||||
#endif
|
||||
return rv;
|
||||
|
||||
}
|
||||
|
||||
/* rm -rf path
|
||||
*
|
||||
* We run as root, so be extra careful when deleting folders.
|
||||
* We only delete folders owned by telemetry:telemetry.
|
||||
* As for the files, they can be owned by root.
|
||||
*/
|
||||
static int rm_rf(char *path)
|
||||
{
|
||||
struct stat info;
|
||||
if (stat(path, &info) == 0) {
|
||||
struct passwd *pw = getpwuid(info.st_uid);
|
||||
if (pw == NULL) {
|
||||
perror("getpwuid");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(pw->pw_name, "telemetry") != 0) {
|
||||
fprintf(stderr, "Not removing \"%s\": Incorrect folder owner \"%s\"\n",
|
||||
path, pw->pw_name);
|
||||
return -1;
|
||||
}
|
||||
struct group *gr = getgrgid(info.st_gid);
|
||||
if (gr == NULL) {
|
||||
perror("getgrgid");
|
||||
return -1;
|
||||
}
|
||||
if (strcmp(gr->gr_name, "telemetry") != 0) {
|
||||
fprintf(stderr, "Not removing \"%s\": Incorrect folder group \"%s\"\n",
|
||||
path, gr->gr_name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS);
|
||||
} else {
|
||||
// Some folders are subfolders of folders already recursivley deleted.
|
||||
// So they may not exist anymore.
|
||||
if (errno != ENOENT) {
|
||||
fprintf(stderr, "file: %s :", path);
|
||||
perror("stat");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Script code:
|
||||
|
||||
telem_remove_work_dirs() {
|
||||
# Remove dirs
|
||||
awk '/^d/{print $2}' ${TELEM_WRK_DIRS_CONF} | xargs rm -rf;
|
||||
}
|
||||
|
||||
Notes:
|
||||
Parse /usr/lib/tmpfiles.d/telemetrics-dirs.conf
|
||||
This file was used to create the folders needed by telemetry.
|
||||
Now we want to delete them. The file contents is as:
|
||||
|
||||
d /usr/local/var/lib/telemetry 0755 telemetry telemetry -
|
||||
d /usr/local/var/spool/telemetry 0750 telemetry telemetry -
|
||||
d /usr/local/var/log/telemetry 0750 telemetry telemetry -
|
||||
d /usr/local/var/log/telemetry/records 0750 telemetry telemetry -
|
||||
d /usr/local/var/cache/telemetry 0750 telemetry telemetry -
|
||||
d /usr/local/var/cache/telemetry/pstore 0750 telemetry telemetry -
|
||||
*/
|
||||
static int telemctl_remove_work_dirs(void)
|
||||
{
|
||||
FILE *fp = fopen(TELEM_WRK_DIRS_CONF, "r");
|
||||
if (fp == NULL){
|
||||
fprintf(stderr, "Could not open file %s", TELEM_WRK_DIRS_CONF);
|
||||
return 1;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
char folder[PATH_MAX+1];
|
||||
char line[PATH_MAX+30];
|
||||
|
||||
if (fgets(line, sizeof(line), fp) == NULL) {
|
||||
if (ferror(fp)) {
|
||||
fprintf(stderr, "Error reading file %s\n", TELEM_WRK_DIRS_CONF);
|
||||
fclose(fp);
|
||||
return 1;
|
||||
}
|
||||
// EOF
|
||||
break;
|
||||
}
|
||||
|
||||
int ret = sscanf(line, "d %s %*s telemetry telemetry - \n", folder);
|
||||
if (ret == 1) {
|
||||
/* Delete the folder. We may get an error trying to delete
|
||||
* folders already deleted. We ignore them, so don't bother
|
||||
* checking rmrtf return value */
|
||||
rm_rf(folder);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mk_telem_dir(void)
|
||||
{
|
||||
char buff[512];
|
||||
int status;
|
||||
struct stat sb;
|
||||
|
||||
if (stat(TELEM_DIR, &sb) == 0 && S_ISDIR(sb.st_mode)) {
|
||||
#ifdef DEBUG
|
||||
printf("[debug] [%s] Folder %s exists\n", __func__, TELEM_DIR);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
memset(buff, 0, sizeof(buff));
|
||||
|
||||
/* Execute "mkdir -p TM_DIR" */
|
||||
status = syscmd(cmd_mk_telemdir, buff, sizeof(buff));
|
||||
fprintf(stderr, "%s", buff);
|
||||
|
||||
if (status == -1 || buff[0] != 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Script code:
|
||||
|
||||
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
|
||||
}
|
||||
*/
|
||||
static int telemctl_opt_out(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Remove TM_OPT_IN file */
|
||||
if (unlink(TM_OPT_IN) != 0) {
|
||||
if (errno == ENOENT) {
|
||||
fprintf(stderr, "Already opted out. Nothing to do.\n");
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, "Failed to remove %s.\n", TM_OPT_IN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = telemctl_stop();
|
||||
ret |= telemctl_remove_work_dirs();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
Script code:
|
||||
|
||||
telem_opt_in() {
|
||||
[ ! -f $OPT_OUT_FILE ] && exit_ok "Already opted in. Nothing to do."
|
||||
rm -f $OPT_OUT_FILE || exit_err "Failed to remove ${OPT_OUT_FILE}."
|
||||
telem_start
|
||||
}
|
||||
|
||||
Modified to add explicit opt-in
|
||||
*/
|
||||
static int telemctl_opt_in(void)
|
||||
{
|
||||
|
||||
/* Ensure TELEM_DIR exists */
|
||||
if (mk_telem_dir() != 0) {
|
||||
fprintf(stderr, "Failed to create %s\n", TELEM_DIR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Create a brand new file TM_OPT_IN, we may fail because the file exists already.
|
||||
* In that case we are already opted in and we are done here. */
|
||||
int fd = open(TM_OPT_IN, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
if (fd == -1) {
|
||||
if (errno == EEXIST) {
|
||||
fprintf(stderr, "Already opted in. Nothing to do.\n");
|
||||
return 0;
|
||||
} else {
|
||||
fprintf(stderr, "Failed to create %s.\n", TM_OPT_IN);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
close(fd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int journal_cmd(char *cmd)
|
||||
{
|
||||
int status;
|
||||
char buff[256];
|
||||
#ifdef DEBUG
|
||||
printf("[debug] [%s] %s\n", __func__, cmd);
|
||||
#endif
|
||||
FILE *fp = popen(cmd, "r");
|
||||
if (fp == NULL) {
|
||||
perror("popen");
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (fgets(buff, sizeof(buff), fp) != NULL) {
|
||||
printf("%s", buff);
|
||||
}
|
||||
|
||||
status = pclose(fp);
|
||||
if (status == -1) {
|
||||
perror("pclose");
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static char* concatargs(int argc, char** argv)
|
||||
{
|
||||
size_t len = strlen("telem_journal") + 1;
|
||||
for (int i = 2; i < argc; i++) {
|
||||
len += strlen(argv[i]) + 1;
|
||||
}
|
||||
|
||||
char *buff = malloc(len*sizeof(char));
|
||||
|
||||
if (buff != NULL) {
|
||||
buff[0] = '\0';
|
||||
strcat(buff,"telem_journal ");
|
||||
|
||||
for (int i = 2; i < argc; i++) {
|
||||
strcat(buff, argv[i]);
|
||||
strcat(buff, " ");
|
||||
}
|
||||
}
|
||||
|
||||
return buff;
|
||||
}
|
||||
|
||||
static int telemctl_journal(char * x)
|
||||
{
|
||||
journal_cmd(x);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void print_usage(char *str)
|
||||
{
|
||||
printf("%s - Control actions for telemetry services\n\n", str);
|
||||
|
||||
for (int i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) {
|
||||
printf(" %-9s %s\n", commands[i].cmd, commands[i].doc);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, ret = EXIT_SUCCESS;
|
||||
bool is_root;
|
||||
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
if (argc == 1) {
|
||||
print_usage(argv[0]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
is_root = getuid()?false:true;
|
||||
|
||||
for (i = 0; i < sizeof(commands)/sizeof(commands[0]); i++) {
|
||||
if (strcmp(commands[i].cmd, argv[1]) == 0) {
|
||||
if (commands[i].root == true && is_root == false) {
|
||||
fprintf(stderr, "Must be root to run this command. Exiting...\n");
|
||||
exit(1);
|
||||
}
|
||||
/* Special treatment for "journal", it can have cmd line arguments */
|
||||
if (strcmp(argv[1],"journal") != 0) {
|
||||
if (argc != 2) {
|
||||
print_usage(argv[0]);
|
||||
exit(2);
|
||||
}
|
||||
ret = commands[i].f.f1();
|
||||
} else {
|
||||
char *buff = concatargs(argc, argv);
|
||||
if (buff != NULL) {
|
||||
ret = commands[i].f.f2(buff);
|
||||
free(buff);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i == sizeof(commands)/sizeof(commands[0])) {
|
||||
printf("Unknown command passed to %s\n\n", argv[0]);
|
||||
print_usage(argv[0]);
|
||||
exit(2);
|
||||
}
|
||||
|
||||
exit(ret);
|
||||
}
|
||||
+148
-51
@@ -36,7 +36,9 @@
|
||||
#include "log.h"
|
||||
#include "configuration.h"
|
||||
|
||||
void initialize_daemon(TelemDaemon *daemon)
|
||||
static void process_record(TelemDaemon *daemon, client *cl);
|
||||
|
||||
void initialize_probe_daemon(TelemDaemon *daemon)
|
||||
{
|
||||
client_list_head head;
|
||||
LIST_INIT(&head);
|
||||
@@ -80,7 +82,8 @@ bool is_client_list_empty(client_list_head *client_head)
|
||||
return (client_head->lh_first == NULL);
|
||||
}
|
||||
|
||||
void terminate_client(TelemDaemon *daemon, client *cl, nfds_t index)
|
||||
|
||||
static void terminate_client(TelemDaemon *daemon, client *cl, nfds_t index)
|
||||
{
|
||||
/* Remove fd from the pollfds array */
|
||||
del_pollfd(daemon, index);
|
||||
@@ -91,24 +94,40 @@ void terminate_client(TelemDaemon *daemon, client *cl, nfds_t index)
|
||||
remove_client(&(daemon->client_head), cl);
|
||||
}
|
||||
|
||||
bool handle_client(TelemDaemon *daemon, nfds_t ind, client *cl)
|
||||
/*
|
||||
See "tm_send_record" for record retails.
|
||||
|
||||
recv buffer layout:
|
||||
* <uint32_t record_size> : so recv knows how much to read
|
||||
* <custom cfg file field> : optional, variable size (string)
|
||||
* <uint32_t header_size>
|
||||
* <headers + Payload>
|
||||
* <null-byte>
|
||||
|
||||
The routine handle_client only cares about "record_size".
|
||||
However, we need to validate if the record_size is reasonable. We assume the
|
||||
worst case scenario would be a record with max cfg file field. There is no
|
||||
exact way to determine header_size, so we assume each line at most 80 chars.
|
||||
|
||||
*/
|
||||
|
||||
#define MAX_RECORD_SIZE (2*sizeof(uint32_t) + CFG_PREFIX_LENGTH + PATH_MAX + \
|
||||
MAX_PAYLOAD_LENGTH + NUM_HEADERS*80)
|
||||
bool handle_client(TelemDaemon *daemon, nfds_t index, client *cl)
|
||||
{
|
||||
/* For now read data from fd */
|
||||
ssize_t len;
|
||||
size_t record_size = 0;
|
||||
size_t buf_size;
|
||||
bool processed = false;
|
||||
uint32_t record_size;
|
||||
|
||||
if (!cl->buf) {
|
||||
cl->buf = malloc(RECORD_SIZE_LEN);
|
||||
cl->size = RECORD_SIZE_LEN;
|
||||
}
|
||||
if (!cl->buf) {
|
||||
telem_log(LOG_ERR, "Unable to allocate memory, exiting\n");
|
||||
exit(EXIT_FAILURE);
|
||||
if (cl->buf != NULL) {
|
||||
free(cl->buf);
|
||||
cl->buf = NULL;
|
||||
}
|
||||
|
||||
malloc_trim(0);
|
||||
len = recv(cl->fd, cl->buf, RECORD_SIZE_LEN, MSG_PEEK | MSG_DONTWAIT);
|
||||
len = recv(cl->fd, &record_size, RECORD_SIZE_LEN, MSG_PEEK | MSG_DONTWAIT);
|
||||
if (len < 0) {
|
||||
telem_log(LOG_ERR, "Failed to talk to client %d: %s\n", cl->fd,
|
||||
strerror(errno));
|
||||
@@ -120,6 +139,39 @@ bool handle_client(TelemDaemon *daemon, nfds_t ind, client *cl)
|
||||
goto end_client;
|
||||
}
|
||||
|
||||
/* Read the record size first */
|
||||
len = recv(cl->fd, &record_size, RECORD_SIZE_LEN, 0);
|
||||
if (len < 0) {
|
||||
telem_log(LOG_ERR, "Failed to receive data from client"
|
||||
" %d: %s\n", cl->fd, strerror(errno));
|
||||
goto end_client;
|
||||
} else if (len == 0) {
|
||||
telem_log(LOG_DEBUG, "End of transmission for client"
|
||||
" %d\n", cl->fd);
|
||||
goto end_client;
|
||||
}
|
||||
|
||||
/* Now that we know the record size, allocate a new buffer
|
||||
* for the record body. We don't need to record size itself in the body.
|
||||
*/
|
||||
|
||||
if (record_size <= RECORD_SIZE_LEN || record_size > MAX_RECORD_SIZE) {
|
||||
telem_log(LOG_ERR, "Record size %u greater tham maximum allowed %lu."
|
||||
"Recored ignored\n", record_size,
|
||||
MAX_RECORD_SIZE);
|
||||
goto end_client;
|
||||
}
|
||||
|
||||
buf_size = record_size - RECORD_SIZE_LEN;
|
||||
cl->buf = calloc(1, buf_size);
|
||||
if (!cl->buf) {
|
||||
telem_log(LOG_ERR, "Unable to allocate memory, exiting\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
cl->size = buf_size;
|
||||
cl->offset = 0;
|
||||
|
||||
/* Read the actual record*/
|
||||
do {
|
||||
malloc_trim(0);
|
||||
len = recv(cl->fd, cl->buf + cl->offset, cl->size - cl->offset, 0);
|
||||
@@ -134,45 +186,20 @@ bool handle_client(TelemDaemon *daemon, nfds_t ind, client *cl)
|
||||
}
|
||||
|
||||
cl->offset += (size_t)len;
|
||||
if (cl->offset < RECORD_SIZE_LEN) {
|
||||
continue;
|
||||
}
|
||||
if (cl->size == RECORD_SIZE_LEN) {
|
||||
record_size = *(uint32_t *)(cl->buf);
|
||||
telem_log(LOG_DEBUG, "Total size of record: %zu\n", record_size);
|
||||
if (record_size == 0) { //record_size < RECORD_MIN_SIZE || record_size > RECORD_MAX_SIZE
|
||||
goto end_client;
|
||||
}
|
||||
// We just processed the record size field, so the remaining format
|
||||
// is (header size field + record body + terminating '\0' byte)
|
||||
cl->size = sizeof(uint32_t) + record_size + 1;
|
||||
cl->buf = realloc(cl->buf, cl->size);
|
||||
memset(cl->buf, 0, cl->size);
|
||||
cl->offset = 0;
|
||||
if (!cl->buf) {
|
||||
telem_log(LOG_ERR, "Unable to allocate memory, exiting\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if (cl->offset != cl->size) {
|
||||
/* full record not received yet */
|
||||
continue;
|
||||
}
|
||||
if (cl->size != RECORD_SIZE_LEN) {
|
||||
/* entire record has been received */
|
||||
|
||||
if (cl->offset == cl->size) {
|
||||
process_record(daemon, cl);
|
||||
/* TODO: cleanup or terminate? */
|
||||
cl->offset = 0;
|
||||
cl->size = RECORD_SIZE_LEN;
|
||||
free(cl->buf);
|
||||
cl->buf = NULL;
|
||||
processed = true;
|
||||
telem_log(LOG_DEBUG, "Record processed for client %d\n", cl->fd);
|
||||
telem_debug("DEBUG: Record processed for client %d\n", cl->fd);
|
||||
break;
|
||||
}
|
||||
} while (len > 0);
|
||||
|
||||
end_client:
|
||||
telem_log(LOG_DEBUG, "Processed client %d: %s\n", cl->fd, processed ? "true" : "false");
|
||||
terminate_client(daemon, cl, ind);
|
||||
terminate_client(daemon, cl, index);
|
||||
return processed;
|
||||
}
|
||||
|
||||
@@ -222,14 +249,14 @@ char *read_machine_id_override()
|
||||
return machine_override;
|
||||
}
|
||||
|
||||
void machine_id_replace(char **machine_header, char *machine_id_override)
|
||||
static void machine_id_replace(char **machine_header, char *machine_id_override)
|
||||
{
|
||||
char machine_id[33] = { 0 };
|
||||
char *old_header;
|
||||
int ret;
|
||||
|
||||
if (machine_id_override) {
|
||||
strcpy(machine_id, machine_id_override);
|
||||
strncpy(machine_id, machine_id_override, sizeof(machine_id)-1);
|
||||
} else {
|
||||
if (!get_machine_id(machine_id)) {
|
||||
// TODO: decide if error handling is needed here
|
||||
@@ -247,7 +274,58 @@ void machine_id_replace(char **machine_header, char *machine_id_override)
|
||||
free(old_header);
|
||||
}
|
||||
|
||||
void process_record(TelemDaemon *daemon, client *cl)
|
||||
static void stage_record(char *filepath, char *headers[], char *body, char *cfg_file)
|
||||
{
|
||||
int tmpfd;
|
||||
FILE *tmpfile = NULL;
|
||||
|
||||
telem_debug("DEBUG: filepath:%s\n", filepath);
|
||||
telem_debug("DEBUG: body:%s\n", body);
|
||||
telem_debug("DEBUG: cfg:%s\n", cfg_file);
|
||||
|
||||
if (filepath == NULL) {
|
||||
telem_log(LOG_ERR, "filepath value must be provided, aborting\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
tmpfd = mkstemp(filepath);
|
||||
if (tmpfd < 0) {
|
||||
telem_perror("Error opening staging file");
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
// access the opened file as a stream
|
||||
tmpfile = fdopen(tmpfd, "a");
|
||||
if (!tmpfile) {
|
||||
telem_perror("Error opening temp stage file");
|
||||
close(tmpfd);
|
||||
if (unlink(filepath)) {
|
||||
telem_perror("Error deleting temp stage file");
|
||||
}
|
||||
goto clean_exit;
|
||||
}
|
||||
|
||||
// write cfg info if exists
|
||||
if (cfg_file != NULL) {
|
||||
fprintf(tmpfile, "%s%s\n", CFG_PREFIX, cfg_file);
|
||||
}
|
||||
|
||||
// write headers
|
||||
for (int i = 0; i < NUM_HEADERS; i++) {
|
||||
fprintf(tmpfile, "%s\n", headers[i]);
|
||||
}
|
||||
|
||||
// write body
|
||||
fprintf(tmpfile, "%s\n", body);
|
||||
fflush(tmpfile);
|
||||
fclose(tmpfile);
|
||||
|
||||
clean_exit:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void process_record(TelemDaemon *daemon, client *cl)
|
||||
{
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
@@ -259,11 +337,30 @@ void process_record(TelemDaemon *daemon, client *cl)
|
||||
char *msg;
|
||||
char *body;
|
||||
char *recordpath = NULL;
|
||||
char *cfg_file = NULL;;
|
||||
size_t cfg_info_size = 0;
|
||||
uint8_t *buf;
|
||||
|
||||
header_size = *(uint32_t *)cl->buf;
|
||||
message_size = cl->size - header_size;
|
||||
buf = cl->buf;
|
||||
|
||||
/* Check for an optional CFG_PREFIX in the first 32 bits */
|
||||
if (*(uint32_t *)buf == CFG_PREFIX_32BIT) {
|
||||
char *cfg = (char *)cl->buf;
|
||||
|
||||
cfg_file = cfg + CFG_PREFIX_LENGTH;
|
||||
cfg_info_size = CFG_PREFIX_LENGTH + strlen(cfg_file) + 1;
|
||||
telem_debug("DEBUG: cfg_file: %s\n", cfg_file);
|
||||
}
|
||||
|
||||
buf += cfg_info_size;
|
||||
header_size = *(uint32_t *)buf;
|
||||
message_size = cl->size - (cfg_info_size + header_size);
|
||||
telem_debug("DEBUG: cl->size: %zu\n", cl->size);
|
||||
telem_debug("DEBUG: header_size: %zu\n", header_size);
|
||||
telem_debug("DEBUG: message_size: %zu\n", message_size);
|
||||
telem_debug("DEBUG: cfg_info_size: %zu\n", cfg_info_size);
|
||||
assert(message_size > 0); //TODO:Check for min and max limits
|
||||
msg = (char *)cl->buf + sizeof(uint32_t);
|
||||
msg = (char *)buf + sizeof(uint32_t);
|
||||
|
||||
/* Copying the headers as strtok modifies the orginal buffer */
|
||||
temp_headers = strndup(msg, header_size);
|
||||
@@ -293,7 +390,7 @@ void process_record(TelemDaemon *daemon, client *cl)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
stage_record(recordpath, headers, body);
|
||||
stage_record(recordpath, headers, body, cfg_file);
|
||||
free(recordpath);
|
||||
end:
|
||||
free(temp_headers);
|
||||
@@ -356,7 +453,7 @@ bool get_machine_id(char *machine_id)
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = fscanf(id_file, "%s", machine_id);
|
||||
ret = fscanf(id_file, "%32s", machine_id);
|
||||
if (ret != 1) {
|
||||
telem_perror("Could not read machine id from file");
|
||||
fclose(id_file);
|
||||
|
||||
+1
-22
@@ -62,7 +62,7 @@ typedef struct TelemDaemon {
|
||||
*
|
||||
* @param daemon A pointer to the daemon structure.
|
||||
*/
|
||||
void initialize_daemon(TelemDaemon *daemon);
|
||||
void initialize_probe_daemon(TelemDaemon *daemon);
|
||||
|
||||
/**
|
||||
* Add poll fd struct to the array of pollfds.
|
||||
@@ -125,27 +125,6 @@ void remove_client(client_list_head *client_head, client *cl);
|
||||
*/
|
||||
bool is_client_list_empty(client_list_head *client_head);
|
||||
|
||||
/**
|
||||
* Terminate a client connection
|
||||
*
|
||||
* @param daemon Pointer to the daemon
|
||||
* @param cl Pointer to the client in the client list
|
||||
* @param index The index of the client file descriptor in the poll fd
|
||||
* array
|
||||
*
|
||||
*/
|
||||
void terminate_client(TelemDaemon *daemon, client *cl, nfds_t index);
|
||||
|
||||
/**
|
||||
* Process record from a client
|
||||
*
|
||||
* @param daemon Pointer to the daemon
|
||||
* @param cl Pointer to the client in the client list
|
||||
*
|
||||
* @return true on success, false on failure
|
||||
*/
|
||||
void process_record(TelemDaemon *daemon, client *cl);
|
||||
|
||||
/**
|
||||
* Get random machine id stored in file
|
||||
*
|
||||
|
||||
+104
-119
@@ -35,6 +35,7 @@
|
||||
#include "common.h"
|
||||
#include "configuration.h"
|
||||
#include "telemetry.h"
|
||||
#include "log.h"
|
||||
|
||||
/**
|
||||
* Return a file descriptor to either site's version file
|
||||
@@ -76,9 +77,7 @@ static int set_header(char **dest, const char *prefix, char *value, size_t *head
|
||||
rc = asprintf(dest, "%s: %s\n", prefix, value);
|
||||
|
||||
if (rc < 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "CRIT: Out of memory\n");
|
||||
#endif
|
||||
telem_log(LOG_CRIT, "CRIT: Out of memory\n");
|
||||
return -ENOMEM;
|
||||
} else {
|
||||
*header_size += (size_t)rc;
|
||||
@@ -233,35 +232,49 @@ static int set_system_name_header(struct telem_ref *t_ref)
|
||||
int fd;
|
||||
char buf[SMALL_LINE_BUF] = { 0 };
|
||||
char name[SMALL_LINE_BUF] = { 0 };
|
||||
char variant[SMALL_LINE_BUF] = { 0 };
|
||||
|
||||
fd = version_file();
|
||||
if (fd == -1) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "WARNING: Cannot find os-release file\n");
|
||||
#endif
|
||||
telem_log(LOG_WARNING, "WARNING: Cannot find os-release file\n");
|
||||
sprintf(name, "unknown");
|
||||
} else {
|
||||
fs = fdopen(fd, "r");
|
||||
while (fgets(buf, SMALL_LINE_BUF, fs)) {
|
||||
if (sscanf(buf, "ID=%s", name) < 1) {
|
||||
continue;
|
||||
} else {
|
||||
if (sscanf(buf, "ID=%s", name) > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
rewind(fs);
|
||||
while (fgets(buf, SMALL_LINE_BUF, fs)) {
|
||||
if (sscanf(buf, "VARIANT_ID=%s", variant) > 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fclose(fs);
|
||||
|
||||
if (strlen(name) == 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "WARNING: Cannot find os-release field: ID\n");
|
||||
#endif
|
||||
telem_log(LOG_WARNING, "WARNING: Cannot find os-release field: ID\n");
|
||||
sprintf(name, "unknown");
|
||||
}
|
||||
|
||||
fclose(fs);
|
||||
if (strlen(variant) == 0) {
|
||||
snprintf(buf, sizeof(buf), "%s", name);
|
||||
} else {
|
||||
/* We do not want the header to be greater than 80 characters, allow truncation */
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-truncation"
|
||||
if (snprintf(buf, sizeof(buf), "%s_%s", name, variant) > sizeof(buf)) {
|
||||
telem_log(LOG_WARNING, "WARNING: truncating system name header to 80 characters\n");
|
||||
}
|
||||
telem_debug("DEBUG: Found variant OS information: %s\n", variant);
|
||||
#pragma GCC diagnostic pop
|
||||
}
|
||||
}
|
||||
|
||||
return set_header(&(t_ref->record->headers[TM_SYSTEM_NAME]),
|
||||
TM_SYSTEM_NAME_STR, name,
|
||||
TM_SYSTEM_NAME_STR, buf,
|
||||
&(t_ref->record->header_size));
|
||||
|
||||
}
|
||||
@@ -285,9 +298,7 @@ static int set_system_build_header(struct telem_ref *t_ref)
|
||||
|
||||
fd = version_file();
|
||||
if (fd == -1) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "WARNING: Cannot find build version file\n");
|
||||
#endif
|
||||
telem_log(LOG_WARNING, "WARNING: Cannot find build version file\n");
|
||||
sprintf(version, "0");
|
||||
} else {
|
||||
fs = fdopen(fd, "r");
|
||||
@@ -300,9 +311,7 @@ static int set_system_build_header(struct telem_ref *t_ref)
|
||||
}
|
||||
|
||||
if (strlen(version) == 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "WARNING: Cannot find build version number\n");
|
||||
#endif
|
||||
telem_log(LOG_WARNING, "WARNING: Cannot find build version number\n");
|
||||
sprintf(version, "0");
|
||||
}
|
||||
|
||||
@@ -416,7 +425,7 @@ static int set_cpu_model_header(struct telem_ref *t_ref)
|
||||
}
|
||||
} else {
|
||||
model_name = "blank";
|
||||
fprintf(stderr, "NOTICE: Unable to find attribute:%s\n", attr_name);
|
||||
telem_log(LOG_NOTICE, "NOTICE: Unable to find attribute:%s\n", attr_name);
|
||||
}
|
||||
|
||||
status = set_header(
|
||||
@@ -425,9 +434,7 @@ static int set_cpu_model_header(struct telem_ref *t_ref)
|
||||
&(t_ref->record->header_size));
|
||||
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "NOTICE: Unable to open /proc/cpuinfo\n");
|
||||
#endif
|
||||
telem_log(LOG_NOTICE, "NOTICE: Unable to open /proc/cpuinfo\n");
|
||||
status = -1;
|
||||
}
|
||||
|
||||
@@ -461,9 +468,7 @@ static int get_dmi_value(const char *source, const char *key, char **buf)
|
||||
*buf = (char *)malloc(sizeof(char) * SMALL_LINE_BUF);
|
||||
|
||||
if (*buf == NULL) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "CRIT: Out of memory\n");
|
||||
#endif
|
||||
telem_log(LOG_CRIT, "CRIT: Out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@@ -486,9 +491,7 @@ static int get_dmi_value(const char *source, const char *key, char **buf)
|
||||
if (new_size == 0) {
|
||||
old_value = *buf;
|
||||
if (asprintf(buf, "blank") < 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "CRIT: Out of memory\n");
|
||||
#endif
|
||||
telem_log(LOG_CRIT, "CRIT: Out of memory\n");
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
free(old_value);
|
||||
@@ -505,24 +508,18 @@ static int get_dmi_value(const char *source, const char *key, char **buf)
|
||||
if (j == new_size) {
|
||||
old_value = *buf;
|
||||
if (asprintf(buf, "blank") < 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "CRIT: Out of memory\n");
|
||||
#endif
|
||||
telem_log(LOG_CRIT, "CRIT: Out of memory\n");
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
free(old_value);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "NOTICE: Dmi file %s does not exist\n", source);
|
||||
#endif
|
||||
telem_debug("DEBUG: Dmi file %s does not exist\n", source);
|
||||
|
||||
old_value = *buf;
|
||||
if (asprintf(buf, "no_%s_file", key) < 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "CRIT: Out of memory\n");
|
||||
#endif
|
||||
telem_log(LOG_CRIT, "CRIT: Out of memory\n");
|
||||
ret = -ENOMEM;
|
||||
}
|
||||
free(old_value);
|
||||
@@ -916,28 +913,16 @@ int tm_create_record(struct telem_ref **t_ref, uint32_t severity,
|
||||
char *classification, uint32_t payload_version)
|
||||
{
|
||||
int ret = 0;
|
||||
int k = 0;
|
||||
struct stat unused;
|
||||
|
||||
k = stat(TM_OPT_OUT_FILE, &unused);
|
||||
if (k == 0) {
|
||||
// Bail early if opt-out is enabled
|
||||
return -ECONNREFUSED;
|
||||
}
|
||||
|
||||
*t_ref = (struct telem_ref *)malloc(sizeof(struct telem_ref));
|
||||
if (*t_ref == NULL) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "CRIT: Out of memory\n");
|
||||
#endif
|
||||
telem_log(LOG_CRIT, "CRIT: Out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
(*t_ref)->record = (struct telem_record *)malloc(sizeof(struct telem_record));
|
||||
if ((*t_ref)->record == NULL) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "CRIT: Out of memory\n");
|
||||
#endif
|
||||
telem_log(LOG_CRIT, "CRIT: Out of memory\n");
|
||||
free(*t_ref);
|
||||
return -ENOMEM;
|
||||
}
|
||||
@@ -991,14 +976,6 @@ int tm_set_payload(struct telem_ref *t_ref, char *payload)
|
||||
{
|
||||
size_t payload_len;
|
||||
int ret = 0;
|
||||
int k = 0;
|
||||
struct stat unused;
|
||||
|
||||
k = stat(TM_OPT_OUT_FILE, &unused);
|
||||
if (k == 0) {
|
||||
// Bail early if opt-out is enabled
|
||||
return -ECONNREFUSED;
|
||||
}
|
||||
|
||||
payload_len = strlen((char *)payload);
|
||||
|
||||
@@ -1010,19 +987,13 @@ int tm_set_payload(struct telem_ref *t_ref, char *payload)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
t_ref->record->payload = (char *)malloc(sizeof(char) * payload_len + 1);
|
||||
t_ref->record->payload = strdup(payload);
|
||||
|
||||
if (!t_ref->record->payload) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "CRIT: Out of memory\n");
|
||||
#endif
|
||||
telem_log(LOG_CRIT, "CRIT: Out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(t_ref->record->payload, 0, sizeof(char) * payload_len + 1);
|
||||
|
||||
strncpy((char *)(t_ref->record->payload), (char *)payload, payload_len);
|
||||
|
||||
t_ref->record->payload_size = payload_len;
|
||||
|
||||
return ret;
|
||||
@@ -1066,7 +1037,7 @@ 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) {
|
||||
if (t_ref && t_ref->record) {
|
||||
// free default id before overriding
|
||||
free(t_ref->record->headers[TM_EVENT_ID]);
|
||||
// set new event_id
|
||||
@@ -1102,10 +1073,7 @@ static int tm_write_socket(int fd, char *buf, size_t nbytes)
|
||||
|
||||
if (b == -1 && errno != EAGAIN) {
|
||||
ret = -errno;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "ERR: Write to daemon socket with"
|
||||
" system error: %s\n", strerror(errno));
|
||||
#endif
|
||||
telem_perror("Error writing to daemon socket");
|
||||
return ret;
|
||||
} else if (b == -1 &&
|
||||
(errno == EAGAIN || errno == EWOULDBLOCK)) {
|
||||
@@ -1145,10 +1113,7 @@ static int tm_get_socket(void)
|
||||
|
||||
if (sfd == -1) {
|
||||
ret = -errno;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "ERR: Attempt to allocate socket fd failed:"
|
||||
" %s\n", strerror(errno));
|
||||
#endif
|
||||
telem_perror("Attempt to allocate socket fd failed");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -1159,10 +1124,7 @@ static int tm_get_socket(void)
|
||||
if (setsockopt(sfd, SOL_SOCKET, SO_RCVTIMEO, &tv,
|
||||
sizeof(tv)) < 0) {
|
||||
ret = -errno;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "ERR: Failed to set socket timeout:"
|
||||
" %s\n", strerror(errno));
|
||||
#endif
|
||||
telem_perror("Failed to set socket timeout");
|
||||
goto out1;
|
||||
}
|
||||
|
||||
@@ -1218,9 +1180,7 @@ static int tm_get_socket(void)
|
||||
// Set non-blocking after the connect() succeeded
|
||||
if ((sflags = fcntl(sfd, F_GETFL, NULL)) < 0) {
|
||||
ret = -errno;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "ERR: Failed to get socket flags\n");
|
||||
#endif
|
||||
telem_log(LOG_ERR, "Failed to get socket flags\n");
|
||||
goto out1;
|
||||
}
|
||||
|
||||
@@ -1228,9 +1188,7 @@ static int tm_get_socket(void)
|
||||
|
||||
if (fcntl(sfd, F_SETFL, sflags) < 0) {
|
||||
ret = -errno;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "ERR: Failed to set socket flags\n");
|
||||
#endif
|
||||
telem_log(LOG_ERR, "Failed to set socket flags\n");
|
||||
goto out1;
|
||||
}
|
||||
|
||||
@@ -1241,6 +1199,17 @@ out1:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int tm_is_opted_in(void)
|
||||
{
|
||||
struct stat unused;
|
||||
|
||||
if (stat(TM_OPT_IN_FILE, &unused) == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int tm_send_record(struct telem_ref *t_ref)
|
||||
{
|
||||
int i;
|
||||
@@ -1250,55 +1219,77 @@ int tm_send_record(struct telem_ref *t_ref)
|
||||
char *data = NULL;
|
||||
size_t offset = 0;
|
||||
int ret = 0;
|
||||
int k = 0;
|
||||
struct stat unused;
|
||||
size_t cfg_file_name_size = 0;
|
||||
const char *cfg_file_name = NULL;
|
||||
|
||||
k = stat(TM_OPT_OUT_FILE, &unused);
|
||||
if (k == 0) {
|
||||
// Bail early if opt-out is enabled
|
||||
if (tm_is_opted_in() == 0) {
|
||||
// Bail early if opt-in is not existent
|
||||
return -ECONNREFUSED;
|
||||
}
|
||||
|
||||
sfd = tm_get_socket();
|
||||
|
||||
if (sfd < 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "ERR: Failed to get socket fd: %s\n",
|
||||
strerror(-sfd));
|
||||
#endif
|
||||
telem_log(LOG_ERR, "Failed to get socket fd: %s\n",
|
||||
strerror(-sfd));
|
||||
return sfd;
|
||||
}
|
||||
|
||||
total_size = t_ref->record->header_size + t_ref->record->payload_size;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: Header size : %zu\n", t_ref->record->header_size);
|
||||
fprintf(stderr, "DEBUG: Payload size : %zu\n", t_ref->record->payload_size);
|
||||
|
||||
fprintf(stderr, "DEBUG: Total size : %zu\n", total_size);
|
||||
#endif
|
||||
/*
|
||||
* The user may want to use a custom (cmd line specified) config file.
|
||||
* If that is the case, we need to include the absolute path in the data packet.
|
||||
* We optionally add the string CFG:<absolute path> as the first string
|
||||
* in the data. If the receiving end sees this in the data, it should
|
||||
* use the config file specified to override any default telemetrics.conf
|
||||
* files.
|
||||
*/
|
||||
|
||||
cfg_file_name = get_cmd_line_config_file();
|
||||
if (cfg_file_name != NULL) {
|
||||
cfg_file_name_size = strlen(cfg_file_name) + 1;
|
||||
total_size += (cfg_file_name_size + CFG_PREFIX_LENGTH);
|
||||
}
|
||||
|
||||
if (cfg_file_name != NULL) {
|
||||
telem_debug("DEBUG: CFG field size : %zu\n", cfg_file_name_size + CFG_PREFIX_LENGTH);
|
||||
telem_debug("DEBUG: CFG file name : %s\n", cfg_file_name);
|
||||
}
|
||||
|
||||
telem_debug("DEBUG: Header size : %zu\n", t_ref->record->header_size);
|
||||
telem_debug("DEBUG: Payload size : %zu\n", t_ref->record->payload_size);
|
||||
|
||||
telem_debug("DEBUG: Total size : %zu\n", total_size);
|
||||
|
||||
/*
|
||||
* Allocating buffer for what we intend to send. Buffer layout is:
|
||||
* <uint32_t total_size><uint32_t header_size><headers + Payload>
|
||||
* <uint32_t record_size> : so recv knows how much to read
|
||||
* <custom cfg file field> : optional
|
||||
* <uint32_t header_size>
|
||||
* <headers + Payload>
|
||||
* <null-byte>
|
||||
* The additional char at the end ensures null termination
|
||||
*/
|
||||
record_size = (2 * sizeof(uint32_t)) + total_size + 1;
|
||||
|
||||
data = malloc(record_size);
|
||||
data = calloc(sizeof(char), record_size);
|
||||
if (!data) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "CRIT: Out of memory\n");
|
||||
#endif
|
||||
telem_log(LOG_CRIT, "CRIT: Out of memory\n");
|
||||
close(sfd);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
memset(data, 0, record_size);
|
||||
|
||||
memcpy(data, &total_size, sizeof(uint32_t));
|
||||
memcpy(data, &record_size, sizeof(uint32_t));
|
||||
offset += sizeof(uint32_t);
|
||||
|
||||
if (cfg_file_name != NULL) {
|
||||
memcpy(data + offset, CFG_PREFIX, CFG_PREFIX_LENGTH);
|
||||
offset += CFG_PREFIX_LENGTH;
|
||||
memcpy(data + offset, cfg_file_name, cfg_file_name_size);
|
||||
offset += cfg_file_name_size;
|
||||
}
|
||||
|
||||
memcpy(data + offset, &t_ref->record->header_size, sizeof(uint32_t));
|
||||
offset += sizeof(uint32_t);
|
||||
|
||||
@@ -1311,17 +1302,11 @@ int tm_send_record(struct telem_ref *t_ref)
|
||||
|
||||
memcpy(data + offset, t_ref->record->payload, t_ref->record->payload_size);
|
||||
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "DEBUG: Data to be sent :\n\n%s\n", data + 2 * sizeof(uint32_t));
|
||||
#endif
|
||||
telem_debug("DEBUG: Data to be sent :\n\n%s\n", data + 2 * sizeof(uint32_t));
|
||||
if ((ret = tm_write_socket(sfd, data, record_size)) == 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "INFO: Successfully sent record over the socket\n");
|
||||
#endif
|
||||
telem_log(LOG_INFO, "INFO: Successfully sent record over the socket\n");
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "ERR: Error while writing data to socket\n");
|
||||
#endif
|
||||
telem_log(LOG_ERR, "Error while writing data to socket\n");
|
||||
}
|
||||
|
||||
close(sfd);
|
||||
|
||||
@@ -120,6 +120,13 @@ int tm_set_payload(struct telem_ref *t_ref, char *payload);
|
||||
*/
|
||||
int tm_send_record(struct telem_ref *t_ref);
|
||||
|
||||
/**
|
||||
* Checks if telemetry was opted in
|
||||
*
|
||||
* @return 1 when opt-in, or 0 when opt-out
|
||||
*/
|
||||
int tm_is_opted_in(void);
|
||||
|
||||
/**
|
||||
* Release the memory allocated to a telemetrics record.
|
||||
*
|
||||
|
||||
@@ -21,3 +21,8 @@ TM_4_0_0 {
|
||||
global:
|
||||
tm_set_event_id;
|
||||
} TM_3_0_0;
|
||||
|
||||
TM_4_1_0 {
|
||||
global:
|
||||
tm_is_opted_in;
|
||||
} TM_4_0_0;
|
||||
|
||||
+60
-26
@@ -178,7 +178,7 @@ static void initialize_record_delivery(TelemPostDaemon *daemon)
|
||||
daemon->record_server_delivery_enabled = record_server_delivery_enabled_config();
|
||||
}
|
||||
|
||||
void initialize_daemon(TelemPostDaemon *daemon)
|
||||
void initialize_post_daemon(TelemPostDaemon *daemon)
|
||||
{
|
||||
assert(daemon);
|
||||
|
||||
@@ -210,7 +210,7 @@ size_t write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
|
||||
return size * nmemb;
|
||||
}
|
||||
|
||||
bool post_record_http(char *headers[], char *body)
|
||||
bool post_record_http(char *headers[], char *body, char *cfg)
|
||||
{
|
||||
CURL *curl;
|
||||
int res = 0;
|
||||
@@ -220,6 +220,22 @@ bool post_record_http(char *headers[], char *body)
|
||||
long http_response = 0;
|
||||
const char *cert_file = get_cainfo_config();
|
||||
const char *tid_header = get_tidheader_config();
|
||||
const char *saved_config_file = NULL;
|
||||
|
||||
if (cfg != NULL) {
|
||||
saved_config_file = get_config_file();
|
||||
if (set_config_file(cfg) != 0) {
|
||||
telem_log(LOG_ERR, "set-config_file(): Failed to set %s\n", cfg);
|
||||
// If we fail to load the specified config file, do not send the
|
||||
// record out. We don't want to send the record out with different
|
||||
// settings than explicitly requested.
|
||||
// However, report success so the record gets deleted.
|
||||
res = 0;
|
||||
goto Done;
|
||||
}
|
||||
reload_config();
|
||||
telem_debug("DEBUG: override server_addr:%s\n", server_addr_config());
|
||||
}
|
||||
|
||||
// Initialize the libcurl global environment once per POST. This lets us
|
||||
// clean up the environment after each POST so that when the daemon is
|
||||
@@ -298,6 +314,17 @@ bool post_record_http(char *headers[], char *body)
|
||||
|
||||
curl_global_cleanup();
|
||||
|
||||
Done:
|
||||
if (saved_config_file != NULL) {
|
||||
if (set_config_file(saved_config_file) != 0) {
|
||||
telem_log(LOG_ERR, "set-config_file(): Failed to set %s",
|
||||
saved_config_file);
|
||||
res = 1;
|
||||
}
|
||||
reload_config();
|
||||
telem_debug("DEBUG: restored server_addr:%s\n", server_addr_config());
|
||||
}
|
||||
|
||||
return res ? false : true;
|
||||
}
|
||||
|
||||
@@ -336,8 +363,8 @@ save_err:
|
||||
|
||||
static void save_entry_to_journal(TelemPostDaemon *daemon, time_t t_stamp, char *headers[])
|
||||
{
|
||||
char *classification_value;
|
||||
char *event_id_value;
|
||||
char *classification_value = NULL;
|
||||
char *event_id_value = NULL;
|
||||
|
||||
if (get_header_value(headers[TM_CLASSIFICATION], &classification_value) &&
|
||||
get_header_value(headers[TM_EVENT_ID], &event_id_value)) {
|
||||
@@ -405,7 +432,7 @@ static void apply_retention_policies(TelemPostDaemon *daemon, char *body)
|
||||
|
||||
/* Deliver record to backend if rate limiting policies are met otherwise
|
||||
* spool record for future delivery */
|
||||
static bool deliver_record(TelemPostDaemon *daemon, char *headers[], char *body)
|
||||
static bool deliver_record(TelemPostDaemon *daemon, char *headers[], char *body, char* cfg_file)
|
||||
{
|
||||
|
||||
bool ret = false;
|
||||
@@ -427,7 +454,7 @@ static bool deliver_record(TelemPostDaemon *daemon, char *headers[], char *body)
|
||||
/* 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);
|
||||
record_sent = post_record_ptr(headers, body, cfg_file);
|
||||
/**
|
||||
* This is the only point where an error condition could be returned
|
||||
* if the record was not sent
|
||||
@@ -469,16 +496,17 @@ bool process_staged_record(char *filename, bool is_retry, TelemPostDaemon *daemo
|
||||
bool ret = false;
|
||||
char *headers[NUM_HEADERS];
|
||||
char *body = NULL;
|
||||
struct stat buf;
|
||||
struct stat buf = { 0 };
|
||||
time_t current_time = time(NULL);
|
||||
int64_t max_spool_size = 0;
|
||||
char *cfg_file = NULL;
|
||||
|
||||
for (k = 0; k < NUM_HEADERS; k++) {
|
||||
headers[k] = NULL;
|
||||
}
|
||||
|
||||
/** Load record **/
|
||||
if ((ret = read_record(filename, headers, &body)) == false) {
|
||||
if ((ret = read_record(filename, headers, &body, &cfg_file)) == false) {
|
||||
telem_log(LOG_WARNING, "unable to read record\n");
|
||||
ret = true; // Record corrupted? true will remove record
|
||||
goto end_processing_file;
|
||||
@@ -492,7 +520,7 @@ bool process_staged_record(char *filename, bool is_retry, TelemPostDaemon *daemo
|
||||
}
|
||||
|
||||
/** Update spool directory size **/
|
||||
(daemon->current_spool_size) += (buf.st_blocks * 512);
|
||||
daemon->current_spool_size += (buf.st_blocks * 512);
|
||||
|
||||
/** Check that record is not expired **/
|
||||
if (!S_ISREG(buf.st_mode) ||
|
||||
@@ -512,9 +540,7 @@ bool process_staged_record(char *filename, bool is_retry, TelemPostDaemon *daemo
|
||||
|
||||
/** Record delivery **/
|
||||
if (!daemon->record_server_delivery_enabled) {
|
||||
#ifdef DEBUG
|
||||
telem_log(LOG_WARNING, "record server delivery disabled\n");
|
||||
#endif
|
||||
telem_log(LOG_INFO, "record server delivery disabled\n");
|
||||
// Not an error condition
|
||||
ret = true;
|
||||
goto end_processing_file;
|
||||
@@ -522,9 +548,7 @@ bool process_staged_record(char *filename, bool is_retry, TelemPostDaemon *daemo
|
||||
|
||||
/** Spool policies **/
|
||||
if (inside_direct_spool_window(daemon, time(NULL))) {
|
||||
#ifdef DEBUG
|
||||
telem_log(LOG_INFO, "process_record: delivering directly to spool\n");
|
||||
#endif
|
||||
/* Check spool max size conf */
|
||||
max_spool_size = spool_max_size_config();
|
||||
if (max_spool_size != -1 &&
|
||||
@@ -545,12 +569,12 @@ bool process_staged_record(char *filename, bool is_retry, TelemPostDaemon *daemo
|
||||
}
|
||||
|
||||
/** Deliver or spool **/
|
||||
ret = deliver_record(daemon, headers, body);
|
||||
ret = deliver_record(daemon, headers, body, cfg_file);
|
||||
|
||||
end_processing_file:
|
||||
/** Update spool size if record will be removed **/
|
||||
if (ret) {
|
||||
(daemon->current_spool_size) -= (buf.st_blocks * 512);
|
||||
daemon->current_spool_size -= (buf.st_blocks * 512);
|
||||
}
|
||||
telem_log(LOG_DEBUG, "spool_size: %ld\n", daemon->current_spool_size);
|
||||
free(body);
|
||||
@@ -559,6 +583,9 @@ end_processing_file:
|
||||
free(headers[k]);
|
||||
}
|
||||
|
||||
if (cfg_file != NULL) {
|
||||
free(cfg_file);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -616,7 +643,8 @@ int staging_records_loop(TelemPostDaemon *daemon)
|
||||
void run_daemon(TelemPostDaemon *daemon)
|
||||
{
|
||||
int ret;
|
||||
int retry_attempt = MAX_RETRY_ATTEMPTS;
|
||||
/* retry_attempt of zero indicates we don't need to retry */
|
||||
int retry_attempt = 0;
|
||||
int spool_process_time = spool_process_time_config();
|
||||
bool daemon_recycling_enabled = daemon_recycling_enabled_config();
|
||||
time_t last_spool_run_time = time(NULL);
|
||||
@@ -627,7 +655,7 @@ void run_daemon(TelemPostDaemon *daemon)
|
||||
assert(daemon->pollfds[signlfd].fd);
|
||||
assert(daemon->pollfds[watchfd].fd);
|
||||
|
||||
/* Post at boot failed initialize retries variable */
|
||||
/* If we failed to send spooled records, indicate we need to retry */
|
||||
if (daemon->bypass_http_post_ts != 0) {
|
||||
retry_attempt = 1;
|
||||
}
|
||||
@@ -636,7 +664,8 @@ void run_daemon(TelemPostDaemon *daemon)
|
||||
int retry_delay = spool_process_time;
|
||||
malloc_trim(0);
|
||||
|
||||
if (retry_attempt < MAX_RETRY_ATTEMPTS) {
|
||||
/* check if we need to retry sending spooled records */
|
||||
if (retry_attempt > 0) {
|
||||
retry_delay = retry_attempt * retry_attempt;
|
||||
daemon->bypass_http_post_ts = 0;
|
||||
telem_log(LOG_INFO, "Record delivery failed will retry in %d seconds",
|
||||
@@ -712,18 +741,23 @@ void run_daemon(TelemPostDaemon *daemon)
|
||||
telem_log(LOG_INFO, "Telemetry post daemon exiting for recycling\n");
|
||||
break;
|
||||
}
|
||||
/* Check if this is a retry */
|
||||
if (retry_attempt < MAX_RETRY_ATTEMPTS) {
|
||||
|
||||
/* Check if this was a retry attempt */
|
||||
if (retry_attempt > 0) {
|
||||
/* Stop attempting retries if successful, increment counter if not */
|
||||
if (staging_records_loop(daemon) == 0) {
|
||||
retry_attempt = MAX_RETRY_ATTEMPTS + 1;
|
||||
retry_attempt = 0;
|
||||
} else {
|
||||
retry_attempt++;
|
||||
}
|
||||
} else if (retry_attempt == MAX_RETRY_ATTEMPTS) {
|
||||
retry_attempt = MAX_RETRY_ATTEMPTS + 1;
|
||||
telem_log(LOG_ERR, "Record deliver failed after %d attempts",
|
||||
MAX_RETRY_ATTEMPTS);
|
||||
/* Give up if counter reaches MAX_RETRY_ATTEMPTS */
|
||||
if (retry_attempt == MAX_RETRY_ATTEMPTS) {
|
||||
telem_log(LOG_ERR, "Record deliver failed after %d attempts",
|
||||
MAX_RETRY_ATTEMPTS);
|
||||
retry_attempt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check spool */
|
||||
if (difftime(now, last_spool_run_time) >= spool_process_time) {
|
||||
spool_records_loop(&(daemon->current_spool_size));
|
||||
|
||||
@@ -65,7 +65,7 @@ typedef struct TelemPostDaemon {
|
||||
*
|
||||
* @param daemon a pointer to telemetry post daemon
|
||||
*/
|
||||
void initialize_daemon(TelemPostDaemon *daemon);
|
||||
void initialize_post_daemon(TelemPostDaemon *daemon);
|
||||
|
||||
/**
|
||||
* Starts daemon
|
||||
@@ -105,8 +105,10 @@ int staging_records_loop(TelemPostDaemon *daemon);
|
||||
*
|
||||
* @param headers a pointer to an array with keys and values
|
||||
* @param body a pointer to the payload
|
||||
* @param cfg_file a pointer to a non-default configuration
|
||||
* file to be used.
|
||||
*/
|
||||
bool post_record_http(char *headers[], char *body);
|
||||
bool post_record_http(char *headers[], char *body, char *cfg_file);
|
||||
|
||||
/**
|
||||
* Pointer to function to isolate backend call during
|
||||
@@ -115,7 +117,7 @@ bool post_record_http(char *headers[], char *body);
|
||||
* @param headers pointer to array of keys
|
||||
* @param body a pinter to payload
|
||||
* */
|
||||
extern bool (*post_record_ptr)(char *headers[], char *body);
|
||||
extern bool (*post_record_ptr)(char *headers[], char *body, char *cfg_file);
|
||||
|
||||
/** Helper functions **/
|
||||
/* rate limit check */
|
||||
|
||||
+6
-14
@@ -33,6 +33,7 @@
|
||||
|
||||
#include "common.h"
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
|
||||
bool get_header(const char *haystack, const char *needle, char **line)
|
||||
{
|
||||
@@ -64,7 +65,7 @@ bool get_header_value(const char *header, char **value)
|
||||
*value = strdup(sep);
|
||||
}
|
||||
|
||||
return (bool)(value != NULL);
|
||||
return (bool)(*value != NULL);
|
||||
}
|
||||
|
||||
void *reallocate(void **addr, size_t *allocated, size_t requested)
|
||||
@@ -100,10 +101,7 @@ long get_directory_size(const char *dir_path)
|
||||
dir = opendir(dir_path);
|
||||
if (!dir) {
|
||||
ret = -errno;
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "ERR: Error opening spool dir: %s\n",
|
||||
strerror(errno));
|
||||
#endif
|
||||
telem_perror("Error opening spool dir");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -113,19 +111,15 @@ long get_directory_size(const char *dir_path)
|
||||
}
|
||||
ret = asprintf(&file_path, "%s/%s", dir_path, de->d_name);
|
||||
if (ret < 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "CRIT: Cannot allocate memory\n");
|
||||
#endif
|
||||
telem_log(LOG_CRIT, "CRIT: Cannot allocate memory\n");
|
||||
closedir(dir);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = lstat(file_path, &buf);
|
||||
if (ret < 0) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "ERR: Could not stat file %s: %s\n",
|
||||
telem_log(LOG_ERR, "Could not stat file %s: %s\n",
|
||||
file_path, strerror(errno));
|
||||
#endif
|
||||
} else {
|
||||
total_size += (buf.st_blocks * 512);
|
||||
}
|
||||
@@ -204,9 +198,7 @@ int validate_classification(char *classification)
|
||||
}
|
||||
|
||||
if (slashes != 2) {
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr, "ERR: Classification string should have two /s.\n");
|
||||
#endif
|
||||
telem_log(LOG_ERR, "Classification string should have two /s.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+51
-7
@@ -55,18 +55,61 @@ START_TEST(check_read_valid_config)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_read_valid_config_defaults)
|
||||
START_TEST(check_default_config)
|
||||
{
|
||||
char *config_file = TOPSRCDIR "/src/data/example.conf";
|
||||
configuration config = { { 0 }, { 0 }, { 0 }, false, NULL };
|
||||
int ret = set_default_config_values(&config);
|
||||
ck_assert(ret == true);
|
||||
|
||||
ck_assert_str_eq(config.strValues[CONF_SERVER_ADDR], DEFAULT_SERVER_ADDR);
|
||||
ck_assert_str_eq(config.strValues[CONF_SOCKET_PATH], DEFAULT_SOCKET_PATH);
|
||||
ck_assert_str_eq(config.strValues[CONF_SPOOL_DIR], DEFAULT_SPOOL_DIR);
|
||||
ck_assert_str_eq(config.strValues[CONF_RATE_LIMIT_STRATEGY], DEFAULT_RATE_LIMIT_STRATEGY);
|
||||
ck_assert_str_eq(config.strValues[CONF_CAINFO], DEFAULT_CAINFO);
|
||||
ck_assert_str_eq(config.strValues[CONF_TIDHEADER], DEFAULT_TIDHEADER);
|
||||
|
||||
ck_assert_int_eq(config.intValues[CONF_RECORD_EXPIRY], DEFAULT_RECORD_EXPIRY);
|
||||
ck_assert_int_eq(config.intValues[CONF_SPOOL_MAX_SIZE], DEFAULT_SPOOL_MAX_SIZE);
|
||||
ck_assert_int_eq(config.intValues[CONF_SPOOL_PROCESS_TIME], DEFAULT_SPOOL_PROCESS_TIME);
|
||||
ck_assert_int_eq(config.intValues[CONF_RECORD_WINDOW_LENGTH], DEFAULT_RECORD_WINDOW_LENGTH);
|
||||
ck_assert_int_eq(config.intValues[CONF_BYTE_WINDOW_LENGTH], DEFAULT_BYTE_WINDOW_LENGTH);
|
||||
ck_assert_int_eq(config.intValues[CONF_RECORD_BURST_LIMIT], DEFAULT_RECORD_BURST_LIMIT);
|
||||
ck_assert_int_eq(config.intValues[CONF_BYTE_BURST_LIMIT], DEFAULT_BYTE_BURST_LIMIT);
|
||||
|
||||
ck_assert(config.boolValues[CONF_RATE_LIMIT_ENABLED] == DEFAULT_RATE_LIMIT_ENABLED);
|
||||
ck_assert(config.boolValues[CONF_DAEMON_RECYCLING_ENABLED] == DEFAULT_DAEMON_RECYCLING_ENABLED);
|
||||
ck_assert(config.boolValues[CONF_RECORD_RETENTION_ENABLED] == DEFAULT_RECORD_RETENTION_ENABLED);
|
||||
ck_assert(config.boolValues[CONF_RECORD_SERVER_DELIVERY_ENABLED] == DEFAULT_RECORD_SERVER_DELIVERY_ENABLED);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(check_layered_config)
|
||||
{
|
||||
char *config_file = TOPSRCDIR "/src/data/example.2.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);
|
||||
ck_assert_str_eq(config.strValues[CONF_SERVER_ADDR], "http://127.0.0.1");
|
||||
ck_assert_str_eq(config.strValues[CONF_SOCKET_PATH], DEFAULT_SOCKET_PATH);
|
||||
ck_assert_str_eq(config.strValues[CONF_SPOOL_DIR], DEFAULT_SPOOL_DIR);
|
||||
ck_assert_str_eq(config.strValues[CONF_RATE_LIMIT_STRATEGY], DEFAULT_RATE_LIMIT_STRATEGY);
|
||||
ck_assert_str_eq(config.strValues[CONF_CAINFO], "/tmp/cacert.crt");
|
||||
ck_assert_str_eq(config.strValues[CONF_TIDHEADER], DEFAULT_TIDHEADER);
|
||||
|
||||
ck_assert_int_eq(config.intValues[CONF_RECORD_EXPIRY], DEFAULT_RECORD_EXPIRY);
|
||||
ck_assert_int_eq(config.intValues[CONF_SPOOL_MAX_SIZE], DEFAULT_SPOOL_MAX_SIZE);
|
||||
ck_assert_int_eq(config.intValues[CONF_SPOOL_PROCESS_TIME], DEFAULT_SPOOL_PROCESS_TIME);
|
||||
ck_assert_int_eq(config.intValues[CONF_RECORD_WINDOW_LENGTH], DEFAULT_RECORD_WINDOW_LENGTH);
|
||||
ck_assert_int_eq(config.intValues[CONF_BYTE_WINDOW_LENGTH], DEFAULT_BYTE_WINDOW_LENGTH);
|
||||
ck_assert_int_eq(config.intValues[CONF_RECORD_BURST_LIMIT], DEFAULT_RECORD_BURST_LIMIT);
|
||||
ck_assert_int_eq(config.intValues[CONF_BYTE_BURST_LIMIT], DEFAULT_BYTE_BURST_LIMIT);
|
||||
|
||||
ck_assert(config.boolValues[CONF_RATE_LIMIT_ENABLED] == DEFAULT_RATE_LIMIT_ENABLED);
|
||||
ck_assert(config.boolValues[CONF_DAEMON_RECYCLING_ENABLED] == DEFAULT_DAEMON_RECYCLING_ENABLED);
|
||||
ck_assert(config.boolValues[CONF_RECORD_RETENTION_ENABLED] == DEFAULT_RECORD_RETENTION_ENABLED);
|
||||
ck_assert(config.boolValues[CONF_RECORD_SERVER_DELIVERY_ENABLED] == DEFAULT_RECORD_SERVER_DELIVERY_ENABLED);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
@@ -117,7 +160,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_default_config);
|
||||
tcase_add_test(t, check_layered_config);
|
||||
tcase_add_test(t, check_read_valid_config_record_retention_delivery);
|
||||
tcase_add_test(t, check_config_initialised);
|
||||
|
||||
|
||||
@@ -41,7 +41,7 @@ void create_setup(void)
|
||||
* with the libcheck API...
|
||||
*/
|
||||
ck_assert_msg(ret != -ECONNREFUSED,
|
||||
"Opt-out enabled. Opt in to run these tests");
|
||||
"First time opt-in required to run test");
|
||||
}
|
||||
|
||||
START_TEST(record_create_non_null)
|
||||
@@ -98,12 +98,22 @@ void create_teardown(void)
|
||||
}
|
||||
}
|
||||
|
||||
START_TEST(is_opt_in)
|
||||
{
|
||||
int ret;
|
||||
ret = tm_is_opted_in();
|
||||
/* Smoke testing function */
|
||||
ck_assert_msg(ret == 0 || ret == 1,
|
||||
"Something wrong with opt-in check");
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(record_create_invalid_class1)
|
||||
{
|
||||
int ret;
|
||||
ret = tm_create_record(&ref, 1, "t/t", 2000);
|
||||
ck_assert_msg(ret != -ECONNREFUSED,
|
||||
"Opt-out enabled. Opt in to run this test");
|
||||
"First time opt-in required to run test");
|
||||
ck_assert(ret == -EINVAL);
|
||||
}
|
||||
END_TEST
|
||||
@@ -113,7 +123,7 @@ START_TEST(record_create_invalid_class2)
|
||||
int ret;
|
||||
ret = tm_create_record(&ref, 1, "t/t/t/t", 2000);
|
||||
ck_assert_msg(ret != -ECONNREFUSED,
|
||||
"Opt-out enabled. Opt in to run this test");
|
||||
"First time opt-in required to run test");
|
||||
ck_assert(ret == -EINVAL);
|
||||
}
|
||||
END_TEST
|
||||
@@ -126,7 +136,7 @@ START_TEST(record_create_severity_underflow)
|
||||
// Severity of 0 is too low; raise it to 1, the minimum
|
||||
ret = tm_create_record(&ref, 0, "a/a/a", 2000);
|
||||
ck_assert_msg(ret != -ECONNREFUSED,
|
||||
"Opt-out enabled. Opt in to run this test");
|
||||
"First time opt-in required to run test");
|
||||
|
||||
if (asprintf(&result, "%s: %u\n", TM_SEVERITY_STR, 1) < 0) {
|
||||
return;
|
||||
@@ -146,7 +156,7 @@ START_TEST(record_create_severity_overflow)
|
||||
// Severity of 5 is too high; lower it to 4, the maximum
|
||||
ret = tm_create_record(&ref, 5, "b/b/b", 2000);
|
||||
ck_assert_msg(ret != -ECONNREFUSED,
|
||||
"Opt-out enabled. Opt in to run this test");
|
||||
"First time opt-in required to run test");
|
||||
|
||||
if (asprintf(&result, "%s: %u\n", TM_SEVERITY_STR, 4) < 0) {
|
||||
return;
|
||||
@@ -172,7 +182,7 @@ void event_id_setup(void)
|
||||
return;
|
||||
}
|
||||
ck_assert_msg(ret != -ECONNREFUSED,
|
||||
"Opt-out enabled. Opt in to run this test");
|
||||
"First time opt-in required to run test");
|
||||
}
|
||||
|
||||
START_TEST(record_set_event_id)
|
||||
@@ -252,6 +262,10 @@ Suite *lib_suite(void)
|
||||
tcase_add_test(t, record_create_version);
|
||||
suite_add_tcase(s, t);
|
||||
|
||||
t = tcase_create("Opt-in");
|
||||
tcase_add_test(t, is_opt_in);
|
||||
suite_add_tcase(s, t);
|
||||
|
||||
t = tcase_create("invalid classification");
|
||||
tcase_add_test(t, record_create_invalid_class1);
|
||||
tcase_add_test(t, record_create_invalid_class2);
|
||||
|
||||
@@ -1,192 +0,0 @@
|
||||
/*
|
||||
* 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: */
|
||||
+3
-3
@@ -27,19 +27,19 @@
|
||||
|
||||
TelemPostDaemon tdaemon;
|
||||
|
||||
bool dummy_post(char *headers[], char *body)
|
||||
bool dummy_post(char *headers[], char *body, char *cfg_file)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool (*post_record_ptr)(char *headers[], char *body) = dummy_post;
|
||||
bool (*post_record_ptr)(char *headers[], char *body, char *cfg_file) = dummy_post;
|
||||
|
||||
void setup(void)
|
||||
{
|
||||
char *config_file = ABSTOPSRCDIR "/src/data/example.conf";
|
||||
set_config_file(config_file);
|
||||
|
||||
initialize_daemon(&tdaemon);
|
||||
initialize_post_daemon(&tdaemon);
|
||||
}
|
||||
|
||||
START_TEST(check_daemon_is_initialized)
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ void setup(void)
|
||||
char *config_file = ABSTOPSRCDIR "/src/data/example.conf";
|
||||
set_config_file(config_file);
|
||||
|
||||
initialize_daemon(&tdaemon);
|
||||
initialize_probe_daemon(&tdaemon);
|
||||
}
|
||||
|
||||
START_TEST(check_daemon_is_initialized)
|
||||
|
||||
@@ -29,14 +29,17 @@
|
||||
#include "src/probes/klog_scanner.h"
|
||||
#include "src/probes/oops_parser.h"
|
||||
|
||||
char reason[1024];
|
||||
nc_string *bt;
|
||||
nc_string *pl;
|
||||
static char reason[1024];
|
||||
static nc_string *pl;
|
||||
|
||||
void callback_func(struct oops_log_msg *msg)
|
||||
{
|
||||
strncpy(reason, msg->lines[0], strlen(msg->lines[0]) + 1);
|
||||
|
||||
size_t len = strlen(msg->lines[0]) + 1;
|
||||
if (len > sizeof(reason)) {
|
||||
len = sizeof(reason);
|
||||
}
|
||||
memcpy(reason, msg->lines[0], len);
|
||||
reason[sizeof(reason) - 1] = 0;
|
||||
pl = parse_payload(msg);
|
||||
}
|
||||
|
||||
|
||||
+21
-20
@@ -15,7 +15,6 @@ check_PROGRAMS = \
|
||||
%D%/check_probd \
|
||||
%D%/check_postd \
|
||||
%D%/check_probes \
|
||||
%D%/check_ncb64 \
|
||||
%D%/check_journal \
|
||||
%D%/check_libtelemetry
|
||||
|
||||
@@ -33,6 +32,13 @@ dist_check_SCRIPTS = \
|
||||
@CHECK_LIBS@ \
|
||||
$(top_builddir)/src/libtelem-shared.la
|
||||
|
||||
if HAVE_SYSTEMD_JOURNAL
|
||||
if LOG_SYSTEMD
|
||||
%C%_check_config_CFLAGS += $(SYSTEMD_JOURNAL_CFLAGS)
|
||||
%C%_check_config_LDADD += $(SYSTEMD_JOURNAL_LIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
%C%_check_probd_SOURCES = \
|
||||
%D%/check_probd.c \
|
||||
src/telemdaemon.c \
|
||||
@@ -148,25 +154,6 @@ 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.c \
|
||||
@@ -180,6 +167,13 @@ EXTRA_DIST += \
|
||||
%C%_check_journal_LDADD = \
|
||||
@CHECK_LIBS@
|
||||
|
||||
if HAVE_SYSTEMD_JOURNAL
|
||||
if LOG_SYSTEMD
|
||||
%C%_check_journal_CFLAGS += $(SYSTEMD_JOURNAL_CFLAGS)
|
||||
%C%_check_journal_LDADD += $(SYSTEMD_JOURNAL_LIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
%C%_check_libtelemetry_SOURCES = \
|
||||
%D%/check_libtelemetry.c \
|
||||
src/configuration.h \
|
||||
@@ -195,4 +189,11 @@ EXTRA_DIST += \
|
||||
$(top_builddir)/src/libtelemetry.la \
|
||||
$(top_builddir)/src/libtelem-shared.la
|
||||
|
||||
if HAVE_SYSTEMD_JOURNAL
|
||||
if LOG_SYSTEMD
|
||||
%C%_check_libtelemetry_CFLAGS += $(SYSTEMD_JOURNAL_CFLAGS)
|
||||
%C%_check_libtelemetry_LDADD += $(SYSTEMD_JOURNAL_LIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
# vim: filetype=automake tabstop=8 shiftwidth=8 noexpandtab
|
||||
|
||||
Reference in New Issue
Block a user