Compare commits

..
5 Commits
Author SHA1 Message Date
Auke Kok da8a8ef85c Add github actions CI. 2019-11-07 13:58:54 -08:00
Alex Jaramillo 5cbd31cbf2 Require explicit telemctl opt-in
telemetrics-client installation starts when the package is installed,
this change makes sure that to start telemetry the first time two steps
are needed: 1- telemctl opt-in and 2- telemctl start

Signed-off-by: Alex Jaramillo <alex.jch@gmail.com>
2019-10-14 11:02:20 -07:00
Juro Bystricky 4119bdea33 configure.ac: bump version to 2.2.3
Version bump to reflect changes in the package.

Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
2019-10-08 09:53:02 -07:00
Juro Bystricky 2395f6bf3e python-probe.c: remove python probe
Remove all references to python probe. The python exceptions
are handled entirely in Python code. This telemetrics-client
package does not need to be aware of the Python code exception handling
and does not need to make any provisions for it (such as creating
services and directories).
It is the responsibility of Python exception handling to properly
interface with the telemetry library.

Signed-off-by: Juro Bystricky <juro.bystricky@intel.com>
2019-10-08 09:52:35 -07:00
Tian Baofeng bc7e2610ee pstore_probe.c: add ramoops file support in pstore probe for cl telemetry
Add support for ramoops files in pstore probe, get the crash information
from "/sys/fs/pstore/dmesg-ramoops-x" files.
Add the "-f" cmd option support to input runtime config file when
running the probe.

Change-Id: Id7f26d6e07a7c215027b9be039356b2633d4869f
Signed-off-by: Tian Baofeng <baofeng.tian@intel.com>
2019-09-16 14:16:40 -07:00
33 changed files with 215 additions and 431 deletions
+29
View File
@@ -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
-1
View File
@@ -42,7 +42,6 @@ hprobe
bertprobe
crashprobe
journalprobe
pythonprobe
telem-record-gen
klogscanner
pstoreclean
+24 -15
View File
@@ -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
View File
@@ -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
View File
@@ -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).
+6 -5
View File
@@ -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).
+7 -1
View File
@@ -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
+6 -1
View File
@@ -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
View File
@@ -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
+1 -1
View File
@@ -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]
+1 -1
View File
@@ -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 -1
View File
@@ -1,6 +1,6 @@
[Unit]
Description=Daily Heartbeat for Telemetrics
ConditionPathExists=!/etc/telemetrics/opt-out
ConditionPathExists=/etc/telemetrics/opt-in
[Timer]
OnCalendar=daily
+1 -1
View File
@@ -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
+1 -1
View File
@@ -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
-12
View File
@@ -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 \
+1
View File
@@ -2,6 +2,7 @@
Description=Telemetrics Pstore Probe
Requires=telemprobd.socket
After=telemprobd.socket
ConditionPathExists=/etc/telemetrics/opt-in
[Service]
ExecStart=@bindir@/pstoreprobe
-9
View File
@@ -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
-13
View File
@@ -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
-2
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -1,6 +1,6 @@
[Unit]
Description=Telemetrics Post Daemon
ConditionPathExists=!/etc/telemetrics/opt-out
ConditionPathExists=/etc/telemetrics/opt-in
[Service]
ExecStart=@bindir@/telempostd
+1 -1
View File
@@ -1,6 +1,6 @@
[Unit]
Description=Telemetrics Daemon
ConditionPathExists=!/etc/telemetrics/opt-out
ConditionPathExists=/etc/telemetrics/opt-in
[Service]
ExecStart=@bindir@/telemprobd
+1 -1
View File
@@ -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
View File
@@ -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
-2
View File
@@ -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.
-15
View File
@@ -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)
+41 -1
View File
@@ -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;
}
-293
View File
@@ -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
View File
@@ -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
View File
@@ -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;
}
+7
View File
@@ -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.
*
+5
View File
@@ -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;
+20 -6
View File
@@ -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);