mirror of
https://github.com/clearlinux/telemetrics-client.git
synced 2026-09-01 11:15:51 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
da8a8ef85c | ||
|
|
5cbd31cbf2 | ||
|
|
4119bdea33 | ||
|
|
2395f6bf3e | ||
|
|
bc7e2610ee |
@@ -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
|
||||
@@ -42,7 +42,6 @@ hprobe
|
||||
bertprobe
|
||||
crashprobe
|
||||
journalprobe
|
||||
pythonprobe
|
||||
telem-record-gen
|
||||
klogscanner
|
||||
pstoreclean
|
||||
|
||||
@@ -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
-1
@@ -2,7 +2,7 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ([2.69])
|
||||
AC_INIT([telemetrics-client], [2.2.2], [https://clearlinux.org/])
|
||||
AC_INIT([telemetrics-client], [2.2.3], [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])
|
||||
|
||||
+6
-5
@@ -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).
|
||||
|
||||
@@ -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).
|
||||
|
||||
@@ -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
|
||||
@@ -64,11 +66,15 @@ The function \fBtm_send_record()\fP delivers the record to the local
|
||||
.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
|
||||
===========
|
||||
@@ -49,13 +51,16 @@ The function ``tm_send_record()`` delivers the record to the local
|
||||
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
-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
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
Description=Telemetrics BERT Probe
|
||||
Requires=telemprobd.socket
|
||||
After=telemprobd.socket
|
||||
ConditionPathExists=!/etc/telemetrics/opt-out
|
||||
ConditionPathExists=/etc/telemetrics/opt-in
|
||||
ConditionPathExists=/sys/firmware/acpi/tables/data/BERT
|
||||
|
||||
[Service]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -19,8 +19,6 @@ EXTRA_DIST += \
|
||||
%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 \
|
||||
@@ -58,8 +56,6 @@ systemdunit_DATA = \
|
||||
%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 \
|
||||
@@ -96,12 +92,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) < $< > $@
|
||||
|
||||
@@ -125,8 +115,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 \
|
||||
|
||||
@@ -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,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
|
||||
|
||||
+2
-2
@@ -90,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
|
||||
|
||||
|
||||
@@ -19,8 +19,6 @@ The default probes provided along the telemetry client code are:
|
||||
|
||||
* 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.
|
||||
|
||||
@@ -4,24 +4,9 @@ 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_CFLAGS = $(AM_CFLAGS)
|
||||
%C%_pythonprobe_LDADD = $(top_builddir)/src/libtelemetry.la
|
||||
%C%_pythonprobe_LDFLAGS = \
|
||||
$(AM_LDFLAGS) \
|
||||
-pie
|
||||
|
||||
if LOG_SYSTEMD
|
||||
if HAVE_SYSTEMD_JOURNAL
|
||||
%C%_pythonprobe_CFLAGS += $(SYSTEMD_JOURNAL_CFLAGS)
|
||||
%C%_pythonprobe_LDADD += $(SYSTEMD_JOURNAL_LIBS)
|
||||
endif
|
||||
endif
|
||||
|
||||
%C%_hprobe_SOURCES = %D%/hello.c
|
||||
%C%_hprobe_LDADD = $(top_builddir)/src/libtelemetry.la
|
||||
%C%_hprobe_CFLAGS = $(AM_CFLAGS)
|
||||
|
||||
@@ -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>
|
||||
@@ -195,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;
|
||||
@@ -205,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
|
||||
@@ -230,7 +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);
|
||||
telem_debug("DEBUG: Extracted count :%d, part : %d\n", count, part);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
+37
-32
@@ -31,7 +31,7 @@
|
||||
#include <errno.h>
|
||||
|
||||
#define TELEM_DIR "/etc/telemetrics"
|
||||
#define TM_OPT_OUT TELEM_DIR"/opt-out"
|
||||
#define TM_OPT_IN TELEM_DIR"/opt-in"
|
||||
|
||||
#define TELEM_WRK_DIRS_CONF "/usr/lib/tmpfiles.d/telemetrics-dirs.conf"
|
||||
|
||||
@@ -46,7 +46,6 @@ static char *SPECIAL_UNITS[] = {
|
||||
"telempostd.path",
|
||||
"klogscanner.service",
|
||||
"journal-probe-tail.service",
|
||||
"python-probe.path",
|
||||
};
|
||||
|
||||
#define NUM_SPECIAL_UNITS ARRAY_SIZE(SPECIAL_UNITS)
|
||||
@@ -152,14 +151,16 @@ telem_start() {
|
||||
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_OUT, F_OK) == 0) {
|
||||
fprintf(stderr, "Opt out is enabled. Cannot start services.\n");
|
||||
if (access(TM_OPT_IN, F_OK) != 0) {
|
||||
fprintf(stderr, "Opt in to telemetry first.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -312,8 +313,6 @@ Notes:
|
||||
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 -
|
||||
d /var/lib/telemetry/python 01777 telemetry telemetry -
|
||||
d /var/tmp/telemetry 01777 telemetry telemetry -
|
||||
*/
|
||||
static int telemctl_remove_work_dirs(void)
|
||||
{
|
||||
@@ -389,28 +388,21 @@ telem_opt_out() {
|
||||
*/
|
||||
static int telemctl_opt_out(void)
|
||||
{
|
||||
/* Ensure TELEM_DIR exists */
|
||||
if (mk_telem_dir() != 0) {
|
||||
fprintf(stderr, "Failed to create %s\n", TELEM_DIR);
|
||||
return 1;
|
||||
}
|
||||
int ret;
|
||||
|
||||
/* Create a brand new file TM_OPT_OUT, we mai fail because the file exists already.
|
||||
* In that case we are already opted out and we are done here. */
|
||||
int fd = open(TM_OPT_OUT, O_CREAT|O_EXCL|O_WRONLY, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
|
||||
if (fd == -1) {
|
||||
if (errno == EEXIST) {
|
||||
/* 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;
|
||||
} else {
|
||||
fprintf(stderr, "Failed to create %s.\n", TM_OPT_OUT);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
telemctl_stop();
|
||||
close(fd);
|
||||
return telemctl_remove_work_dirs();
|
||||
}
|
||||
fprintf(stderr, "Failed to remove %s.\n", TM_OPT_IN);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = telemctl_stop();
|
||||
ret |= telemctl_remove_work_dirs();
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -421,20 +413,33 @@ telem_opt_in() {
|
||||
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)
|
||||
{
|
||||
/* Delete the TM_OPT_OUT file */
|
||||
if (unlink(TM_OPT_OUT) == -1) {
|
||||
if (errno == ENOENT) {
|
||||
fprintf(stderr, "Already opted in. Nothing to do.\n");
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, "Failed to remove %s.\n", TM_OPT_OUT);
|
||||
|
||||
/* Ensure TELEM_DIR exists */
|
||||
if (mk_telem_dir() != 0) {
|
||||
fprintf(stderr, "Failed to create %s\n", TELEM_DIR);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return telemctl_start();
|
||||
/* Create a brand new file TM_OPT_IN, we maight 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+13
-5
@@ -1199,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;
|
||||
@@ -1208,14 +1219,11 @@ 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user