Compare commits

..
47 Commits
Author SHA1 Message Date
Patrick McCarty 7d3a9d2834 Release v1.12.0
This release introduces a new feature for the crash probe. It will now
collect source file and line number information for each frame in a
backtrace if the data is available.

Also, this release saw the beginning of migrating the code base to use
libnica instead of glib, with the goal of reducing memory footprint of
the telemetry daemon and probes. Future releases will convert more
existing glib usage to libnica.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-11 13:19:41 -07:00
Patrick McCarty 0af684e94e Fix bug in is_banned_path(); group conditionals
The checks in is_banned_path() for a path prefix not under /usr needed
to be connected with a logical AND, not OR, as implied by the recent
changes.

Also, use an explicit logical OR for the other two groups of
conditionals so that they are grouped similarly to the checks that
required an AND.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-11 12:55:33 -07:00
Patrick McCarty 51374db118 Remove more unused glib includes
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-11 11:22:42 -07:00
Patrick McCarty dfb40babaa Remove unneeded glib.h include
telem-record-gen no longer depends on glib, so the include can be
removed.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-11 10:29:18 -07:00
Patrick McCarty b7619e1a1c Remove glib dependency for ASCII string check
As far as I can tell, the standard library doesn't have a function to
check for an ASCII string. Equivalently, we can iterate over each
character in the string, byte by byte, and verify that only 7-bit
characters are present.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-11 10:29:18 -07:00
Patrick McCarty 3be37cebb5 Use getopt_long() in telem-record-gen
One more binary was using GOptionContext: telem-record-gen. Convert it
to use getopt_long() as well.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-11 10:29:18 -07:00
Patrick McCarty 15a32b6346 Fix code style issues in journal.c
Run uncrustify again to catch further whitespace issues.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-11 10:29:18 -07:00
Patrick McCarty e0e2aae341 Use getopt_long() in the crash probe
Continuing the removal of dependency on glib, switch to use
getopt_long() instead of the GOptionContext API for the crash probe.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-11 10:29:18 -07:00
Arjan van de Ven 4d1f6de3b5 replace the regexps with more simple tests 2017-05-11 09:19:41 -07:00
Patrick McCarty f3a641b161 Use getopt_long() in the journal probe
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-10 12:54:43 -07:00
Patrick McCarty 9018362ffb Fix style issues missed by uncrustify
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-10 12:39:48 -07:00
Patrick McCarty eedcb88cb7 Run uncrustify
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-10 12:07:44 -07:00
Patrick McCarty 2deeef65ad Update path filter for uncrustify
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-10 12:07:26 -07:00
Patrick McCarty dab667eeea Fix distcheck
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-10 12:00:09 -07:00
Patrick McCarty 787102c4fb Clean up makefile and header references for consistency
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-10 11:58:55 -07:00
Arjan van de Ven 12d1c82650 Print file name / line number in backtrace 2017-05-10 11:27:52 -07:00
Arjan van de Ven 46d88d6315 more crash probe glib string removals 2017-05-10 11:27:52 -07:00
Arjan van de Ven 089183c9e0 remove some spurious glib includes 2017-05-10 11:27:52 -07:00
Arjan van de Ven f354078d3d convert the journal probe to getopt 2017-05-10 11:27:52 -07:00
Arjan van de Ven db85aa9a18 stop using g_print 2017-05-10 11:27:52 -07:00
Arjan van de Ven f5899c7ba6 convert more of the crash probe 2017-05-10 11:27:52 -07:00
Arjan van de Ven 657c8792d5 make the pstore probe use nica strings 2017-05-10 11:27:52 -07:00
Arjan van de Ven 365cfeee9a convert the journal probe to nica strings 2017-05-10 11:27:52 -07:00
Arjan van de Ven 4957452f66 convert the crash probe to nica strings 2017-05-10 11:27:52 -07:00
Arjan van de Ven e02e22f192 replace glib string operations with nica string operations 2017-05-10 11:27:52 -07:00
Patrick McCarty 60bbe963cb Fix make check for Travis builds
The libcheck on Ubuntu is too old, so install a newer version to enable
make check.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-05 12:53:33 -07:00
Patrick McCarty 1ffc3a00c2 configure: add comment regarding minimum supported libcheck
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-05-05 12:51:41 -07:00
Patrick McCarty 60edcdb165 Revert "don't be as picky about check"
This reverts commit aa4f9e3058.

The oldest version of libcheck that supports TAP output is 0.9.12, so we
need to use >= 0.9.12.
2017-05-05 12:51:41 -07:00
Arjan van de Ven bc12e6d5f7 the klog_scanner does not use glib.h 2017-05-05 12:18:42 -07:00
Arjan van de Ven e9d29a4e7b use isspace and isprint directly 2017-05-05 12:18:42 -07:00
Arjan van de Ven 6295f0f4dc a gchar is just a char typedef 2017-05-05 12:18:42 -07:00
Arjan van de Ven 4cf3c7e8ac a guint is just an uint32_t so lets use standard types 2017-05-05 12:18:42 -07:00
Arjan van de Ven d9d957e532 make distcheck is b0rk 2017-05-05 16:51:44 +00:00
Arjan van de Ven f88d646ae1 make check is b0rk 2017-05-05 16:49:39 +00:00
Arjan van de Ven e0619807c9 drop flags the OS should provide 2017-05-05 16:47:01 +00:00
Arjan van de Ven f07c9b168c add libdw-dev 2017-05-05 16:42:50 +00:00
Arjan van de Ven 7333bc7968 add libelf-dev 2017-05-05 16:40:11 +00:00
Arjan van de Ven aa4f9e3058 don't be as picky about check 2017-05-05 16:38:13 +00:00
Arjan van de Ven 6c36253351 add check 2017-05-05 16:35:56 +00:00
Arjan van de Ven e78ca8b66f avoid the stone age 2017-05-05 16:33:18 +00:00
Arjan van de Ven a449e6cec1 add autoconf 2017-05-05 16:30:29 +00:00
Arjan van de Ven 5963f983cd one more different package name 2017-05-05 16:27:21 +00:00
Arjan van de Ven c65e58f696 resolve deps 2017-05-05 16:25:54 +00:00
Arjan van de Ven 1d5b2d0669 add first stab travis file 2017-05-05 16:21:36 +00:00
Patrick McCarty 356be6738f Release v1.11.2
This release includes a couple of fixes for the man pages.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2017-04-06 09:59:36 -07:00
Auke Kok e73870b916 Fix wrong reference to the config file in man pages. 2017-04-06 09:57:50 -07:00
Auke Kok c7e783f2b1 Add FILES section, explain static machine id file. 2017-04-06 09:57:50 -07:00
32 changed files with 889 additions and 299 deletions
+36
View File
@@ -0,0 +1,36 @@
dist: trusty
compiler:
- gcc
os:
- linux
before_script:
./autogen.sh
language: c
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- libglib2.0-dev
- libcurl4-gnutls-dev
- valgrind
- autoconf
- automake
- check
- libelf-dev
- libdw-dev
install:
- wget http://downloads.sourceforge.net/project/check/check/0.10.0/check-0.10.0.tar.gz
- tar -xvf check-0.10.0.tar.gz
- pushd check-0.10.0 && ./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu && make -j48 && sudo make install && popd
script:
- ./configure && make && make check
after_failure: cat test-suite.log
+1 -1
View File
@@ -62,7 +62,7 @@ Coding Style
- To make type casts stand out more, include no space between the cast and the
variable, etc. to cast:
GString **foo = (GString **)bar;
nc_string **foo = (nc_string **)bar;
- Whenever arithmetic operators are used, always include one space before and
after each operator:
+1
View File
@@ -18,6 +18,7 @@ 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
include $(top_srcdir)/src/probes/local.mk
include $(top_srcdir)/tests/local.mk
-2
View File
@@ -2,7 +2,6 @@ AM_CFLAGS = \
-std=gnu99 \
-pedantic \
-Wall \
-fstack-protector \
-Wformat \
-Wformat-security \
-Wimplicit-function-declaration \
@@ -12,7 +11,6 @@ AM_CFLAGS = \
-Wconversion \
-Wunreachable-code \
-funsigned-char \
-fstack-protector-strong \
-fPIE \
-fPIC
+3 -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], [1.11.1], [https://clearlinux.org/])
AC_INIT([telemetrics-client], [1.12.0], [https://clearlinux.org/])
AC_CONFIG_AUX_DIR([build-aux])
AM_INIT_AUTOMAKE([1.14 -Wall -Werror -Wno-extra-portability foreign subdir-objects])
AM_SILENT_RULES([yes])
@@ -21,6 +21,8 @@ AC_PROG_LN_S
AC_PROG_MAKE_SET
# Checks for libraries.
# check >= 0.9.12 is required for TAP output
PKG_CHECK_MODULES([CHECK], [check >= 0.9.12])
PKG_CHECK_MODULES([CURL], [libcurl])
PKG_CHECK_MODULES([GLIB], [glib-2.0])
+32 -1
View File
@@ -35,6 +35,10 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
\fBtelemd\fP <flags>
.sp
\fB/etc/telemetrics/telemetrics.conf\fP
.sp
\fB/usr/share/defaults/telemetrics/telemetrics.conf\fP
.sp
\fB/etc/telemetrics/opt\-in\-static\-machine\-id\fP
.SH DESCRIPTION
.sp
The \fBtelemd\fP program delivers locally generated telemetry records to a remote
@@ -55,6 +59,33 @@ Print the program version.
.UNINDENT
.UNINDENT
.UNINDENT
.SH FILES
.INDENT 0.0
.IP \(bu 2
\fB/usr/share/defaults/telemetrics/telemetrics.conf\fP
.INDENT 2.0
.INDENT 3.5
If no custom configuration file is found, \fBtelemd\fP uses the
settings in this file.
.UNINDENT
.UNINDENT
.IP \(bu 2
\fB/etc/telemetrics/telemetrics.conf\fP
.INDENT 2.0
.INDENT 3.5
Custom configuration file that \fBtelemd\fP reads. See \fBtelemetrics.conf\fP(5).
.UNINDENT
.UNINDENT
.IP \(bu 2
\fB/etc/telemetrics/opt\-in\-static\-machine\-id\fP
.INDENT 2.0
.INDENT 3.5
If this file exists, the first line of this file will be sent to
the server as the machine ID. Otherwise, the machine ID will be
random and changed regularly.
.UNINDENT
.UNINDENT
.UNINDENT
.SH EXIT STATUS
.sp
0 when no errors occurred. A non\-zero exit status indicates a failure occurred.
@@ -63,7 +94,7 @@ Print the program version.
.IP \(bu 2
\fBtelemetry\fP(3)
.IP \(bu 2
\fBtelemetrics\-client.conf\fP(5)
\fBtelemetrics.conf\fP(5)
.IP \(bu 2
\fI\%https://github.com/clearlinux/telemetrics\-client\fP
.IP \(bu 2
+25 -1
View File
@@ -17,6 +17,10 @@ SYNOPSIS
``/etc/telemetrics/telemetrics.conf``
``/usr/share/defaults/telemetrics/telemetrics.conf``
``/etc/telemetrics/opt-in-static-machine-id``
DESCRIPTION
===========
@@ -38,6 +42,26 @@ OPTIONS
Print the program version.
FILES
=====
* ``/usr/share/defaults/telemetrics/telemetrics.conf``
If no custom configuration file is found, ``telemd`` uses the
settings in this file.
* ``/etc/telemetrics/telemetrics.conf``
Custom configuration file that ``telemd`` reads. See ``telemetrics.conf``\(5).
* ``/etc/telemetrics/opt-in-static-machine-id``
If this file exists, the first line of this file will be sent to
the server as the machine ID. Otherwise, the machine ID will be
random and changed regularly.
EXIT STATUS
===========
@@ -48,7 +72,7 @@ SEE ALSO
========
* ``telemetry``\(3)
* ``telemetrics-client.conf``\(5)
* ``telemetrics.conf``\(5)
* https://github.com/clearlinux/telemetrics-client
* https://clearlinux.org/documentation/
+1 -1
View File
@@ -14,6 +14,6 @@ if [ "$?" -ne 0 ]; then
exit 1
fi
find .. -path "../*/*.[ch]" -exec uncrustify {} -c tm.cfg --no-backup \;
find .. -path "../*/*.[ch]" ! -path "../src/nica/*" -exec uncrustify {} -c tm.cfg --no-backup \;
# vi: ts=8 sw=2 sts=2 et tw=80
+9 -7
View File
@@ -23,6 +23,8 @@
#include <string.h>
#include <ctype.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "configuration.h"
#include "util.h"
@@ -45,7 +47,7 @@ const char *config_key_int[] = { NULL, "record_expiry", "spool_max_size",
"byte_burst_limit", NULL };
const char *config_key_bool[] = { NULL, "rate_limit_enabled",
"daemon_recycling_enabled", NULL };
"daemon_recycling_enabled", NULL };
static struct configuration config = { { 0 }, { 0 }, { 0 }, false, NULL };
@@ -90,7 +92,7 @@ bool read_config_from_file(char *config_file, struct configuration *config)
keyfile = g_key_file_new();
if (!g_key_file_load_from_file(keyfile, (gchar *)config_file, flags, &error)) {
if (!g_key_file_load_from_file(keyfile, config_file, flags, &error)) {
#ifdef DEBUG
fprintf(stderr, "ERR: Failed to read config file: %s\n",
error->message);
@@ -133,11 +135,11 @@ void initialize_config(void)
/* No config file provided on command line */
if (!config_file) {
if (g_file_test(etc_config_file, G_FILE_TEST_IS_REGULAR)) {
if (access(etc_config_file, R_OK) == 0) {
config_file = etc_config_file;
} else {
if (g_file_test(default_config_file,
G_FILE_TEST_IS_REGULAR)) {
if (access(default_config_file,
R_OK) == 0) {
config_file = default_config_file;
} else {
/* If there is no default config, exit with failure */
@@ -338,7 +340,7 @@ const char *rate_limit_strategy_config()
bool daemon_recycling_enabled_config(void)
{
initialize_config();
return config.boolValues[CONF_DAEMON_RECYCLING_ENABLED];
initialize_config();
return config.boolValues[CONF_DAEMON_RECYCLING_ENABLED];
}
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
+1 -1
View File
@@ -46,7 +46,7 @@ enum config_int_keys {
enum config_bool_keys {
CONF_BOOL_MIN = 0,
CONF_RATE_LIMIT_ENABLED,
CONF_DAEMON_RECYCLING_ENABLED,
CONF_DAEMON_RECYCLING_ENABLED,
CONF_BOOL_MAX
};
+1 -1
View File
@@ -81,7 +81,7 @@
#ifdef TM_LOG_STDERR
#define telem_log(priority, ...) do { \
if (priority <= MAX_LOG_LEVEL) { \
fprintf(stderr, __VA_ARGS__ ); \
fprintf(stderr, __VA_ARGS__); \
} \
} while (0);
#endif
+2 -2
View File
@@ -232,7 +232,7 @@ int main(int argc, char **argv)
time_t last_spool_run_time = time(NULL);
time_t last_daemon_start_time = time(NULL);
bool daemon_recycling_enabled = daemon_recycling_enabled_config();
bool daemon_recycling_enabled = daemon_recycling_enabled_config();
ret = update_machine_id();
if (ret == -1) {
@@ -338,7 +338,7 @@ int main(int argc, char **argv)
} else {
time_t now = time(NULL);
/* If spool is empty and time to recycle the daemon has elapsed*/
if (daemon_recycling_enabled && (daemon.current_spool_size == 0) &&
if (daemon_recycling_enabled && (daemon.current_spool_size == 0) &&
difftime(now, last_daemon_start_time) >= TM_DAEMON_EXIT_TIME) {
/* Exit */
telem_log(LOG_INFO, "Daemon exiting for recycling\n");
+3
View File
@@ -0,0 +1,3 @@
noinst_HEADERS += \
%D%/macros.h \
%D%/nc-string.h
+29
View File
@@ -0,0 +1,29 @@
/*
* This file is part of libnica.
*
* Copyright © 2016-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.
*/
#pragma once
#define _GNU_SOURCE
#define _nica_public_ __attribute__((visibility("default")))
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=8 tabstop=8 expandtab:
* :indentSize=8:tabSize=8:noTabs=true:
*/
+144
View File
@@ -0,0 +1,144 @@
/*
* This file is part of libnica.
*
* Copyright © 2016-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 <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "nc-string.h"
nc_string *nc_string_dup(const char *str)
{
if (!str) {
return NULL;
}
struct nc_string_t *st = calloc(1, sizeof(struct nc_string_t));
if (!st) {
return NULL;
}
st->len = asprintf(&st->str, "%s", str);
if (st->len < 0 || !st->str) {
free(st);
return NULL;
}
return st;
}
nc_string *nc_string_dup_printf(const char *ptn, ...)
{
if (!ptn) {
return NULL;
}
struct nc_string_t *st = calloc(1, sizeof(struct nc_string_t));
if (!st) {
return NULL;
}
va_list va;
va_start(va, ptn);
st->len = vasprintf(&st->str, ptn, va);
if (st->len < 0 || !st->str) {
free(st);
st = NULL;
goto end;
}
end:
va_end(va);
return st;
}
nc_string *nc_string_append_printf(nc_string *st, const char *ptn, ...)
{
char *newstr;
char *newstr2;
int ret;
if (!ptn) {
return NULL;
}
va_list va;
va_start(va, ptn);
ret = vasprintf(&newstr, ptn, va);
if (ret <= 0)
newstr = strdup("");
st->len = asprintf(&newstr2, "%s%s", st->str, newstr);
free(st->str);
st->str = newstr2;
free(newstr);
va_end(va);
return st;
}
bool nc_string_cat(nc_string *s, const char *append)
{
char *p = NULL;
int len = 0;
if (!s || !append) {
return false;
}
if (!s->str) {
return false;
}
len = asprintf(&p, "%s%s", s->str, append);
if (!p || len < s->len) {
return false;
}
free(s->str);
s->str = p;
s->len = len;
return true;
}
bool nc_string_prepend(nc_string *s, const char *prepend)
{
char *p = NULL;
int len = 0;
if (!s || !prepend) {
return false;
}
if (!s->str) {
return false;
}
len = asprintf(&p, "%s%s", prepend, s->str);
if (!p || len < s->len) {
return false;
}
free(s->str);
s->str = p;
s->len = len;
return true;
}
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=8 tabstop=8 expandtab:
* :indentSize=8:tabSize=8:noTabs=true:
*/
+220
View File
@@ -0,0 +1,220 @@
/*
* This file is part of libnica.
*
* Copyright © 2016-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.
*/
#pragma once
#define _GNU_SOURCE
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include "macros.h"
/**
* Safely represent and store a buffer as a string
*/
typedef struct nc_string_t {
char *str; /**<Buffer holding a NUL-terminated string */
int len; /**<Current length of the string */
} nc_string;
/**
* Construct a new string using printf style syntax
*
* @param format Printf-style format string
* @param ... Variable arguments
*
* @return a new nc_string if allocation succeeded, otherwise NULL
*/
_nica_public_ nc_string *nc_string_dup_printf(const char *format, ...)
__attribute__((format(printf, 1, 2)));
_nica_public_ nc_string *nc_string_append_printf(nc_string *st, const char *ptn, ...)
__attribute__((format(printf, 2, 3)));
/**
* Duplicate a string into a new NUL-terminated nc_string
*
* @param str Pointer to a string
* @return a new nc_string if allocation succeeded, otherwise NULL
*/
_nica_public_ nc_string *nc_string_dup(const char *str);
/**
* Free an existing string and its contents
*
* @param str Pointer to an existing string
*/
static inline void nc_string_free(nc_string *str)
{
if (!str) {
return;
}
if (str->str) {
free(str->str);
}
free(str);
}
/**
* Append the contents of 'append' into the given nc_string
*
* @param str Pointer to a valid nc_string
* @param append Text to append into the nc_string
*
* @return a boolean value indicating success
*/
_nica_public_ bool nc_string_cat(nc_string *str, const char *append);
_nica_public_ bool nc_string_prepend(nc_string *s, const char *prepend);
/**
* Determine if string A is equal to string B
*
* @note This function will not check beyond the length of string A
*
* @param a string to check
* @param b string to check against
* @return a boolean value, true if the strings match, otherwise false
*/
static inline bool nc_string_equal(nc_string *a, nc_string *b)
{
if (!a || !b) {
return false;
}
if (!a->str || !b->str) {
return false;
}
return strncmp(a->str, b->str, (size_t)a->len) == 0;
}
/**
* Determine if string A is equal to string B
*
* @note This function will not check beyond the length of string A
*
* @param a string to check
* @param b const char* string to check against
* @return a boolean value, true if the strings match, otherwise false
*/
static inline bool nc_string_const_equal(nc_string *a, const char *b)
{
if (!a || !b) {
return false;
}
if (!a->str) {
return false;
}
return strncmp(a->str, b, (size_t)a->len) == 0;
}
/**
* Convenience wrapper to obtain string length
*
* @note This will assert the string is not NULL, ensuring a termination.
*
* @return length of the given string
*/
static inline int ncstrlen(nc_string *str)
{
assert(str != NULL);
return str->len;
}
/**
* Determine if a string has the given suffix
*
* @param str Valid nc_string
* @param suffix A suffix to check
* @param len Length of the suffix
*
* @return True if @str has the given suffix
*/
static inline bool nc_string_has_suffix_const(nc_string *str, char *suffix, ssize_t len)
{
if (!str || !suffix) {
return false;
}
if (len > str->len || len <= 0) {
return false;
}
return (strncmp(str->str + (str->len - (len)), suffix, (size_t)len) == 0);
}
/**
* Determine if a string has the given prefix
*
* @param str Valid nc_string
* @param prefix A prefix to check
* @param len Length of the prefix
*
* @return True if @str has the given prefix
*/
static inline bool nc_string_has_prefix_const(nc_string *str, char *prefix, ssize_t len)
{
if (!str || !prefix) {
return false;
}
if (len > str->len || len <= 0) {
return false;
}
return (strncmp(str->str, prefix, (size_t)len) == 0);
}
/**
* Perform inplace modification of a strip to return
* a stripped pointer, that is, without start and end whitespace.
*
* This does not modify the length of the string.
*/
static inline char *nc_string_strip(nc_string *str)
{
int i;
if (!str || !str->str) {
return NULL;
}
for (i = 0; i < str->len; i++) {
if (str->str[i] != ' ') {
break;
}
}
for (int j = str->len - 1; j > i; j--) {
if (str->str[j] != ' ') {
str->str[j + 1] = '\0';
break;
}
}
return str->str + i;
}
/**
* To be used only with compile time constants.
*/
#define nc_string_has_suffix(a, suff) nc_string_has_suffix_const(a, suff, (sizeof(suff) - 1))
#define nc_string_has_prefix(a, pref) nc_string_has_prefix_const(a, pref, (sizeof(pref) - 1))
/*
* Editor modelines - https://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: nil
* End:
*
* vi: set shiftwidth=8 tabstop=8 expandtab:
* :indentSize=8:tabSize=8:noTabs=true:
*/
+161 -107
View File
@@ -17,6 +17,7 @@
#define _GNU_SOURCE
#include <assert.h>
#include <fcntl.h>
#include <getopt.h>
#include <grp.h>
#include <inttypes.h>
#include <limits.h>
@@ -31,11 +32,10 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <glib.h>
#include <libelf.h>
#include <elfutils/libdwfl.h>
#include "nica/nc-string.h"
#include "config.h"
#include "log.h"
#include "probe.h"
@@ -54,10 +54,10 @@ static Dwfl *d_core = NULL;
static char *debuginfo_path = "-/usr/lib/debug";
static unsigned int frame_counter = 0;
static gchar *proc_name = NULL;
static char *proc_name = NULL;
static pid_t core_for_pid = 0;
static GString *header = NULL;
static gchar *errorstr = NULL;
static nc_string *header = NULL;
static char *errorstr = NULL;
static uint32_t unknown_severity = 2;
static uint32_t default_severity = 3;
@@ -85,9 +85,17 @@ static inline void tm_dwfl_err(const char *msg)
telem_log(LOG_ERR, "%s: %s\n", msg, dwfl_errmsg(-1));
}
static gchar *replace_exclamations(gchar *str)
static char *replace_exclamations(char *str)
{
return g_strdelimit(str, "!", '/');
char *c;
while (1) {
c = strchr(str, '!');
if (!c) {
break;
}
*c = '/';
}
return str;
}
static void drop_privs(void)
@@ -235,15 +243,20 @@ static int frame_cb(Dwfl_Frame *frame, void *userdata)
Dwarf_Addr pc;
Dwarf_Addr pc_adjusted;
Dwfl_Module *module;
Dwfl_Line *line;
const char *procname;
const char *modname;
bool activation;
GString **bt = (GString **)userdata;
nc_string **bt = (nc_string **)userdata;
if (!dwfl_frame_pc(frame, &pc, &activation)) {
errorstr = g_strdup_printf("Failed to find program counter for"
" current frame: %s\n",
dwfl_errmsg(-1));
int ret;
ret = asprintf(&errorstr, "Failed to find program counter for"
" current frame: %s\n",
dwfl_errmsg(-1));
if (ret < 0) {
return DWARF_CB_ABORT;
}
return DWARF_CB_ABORT;
}
@@ -260,8 +273,8 @@ static int frame_cb(Dwfl_Frame *frame, void *userdata)
module = dwfl_addrmodule(d_core, pc_adjusted);
if (!module) {
errorstr = g_strdup("Failed to find module for current"
" frame\n");
errorstr = strdup("Failed to find module for current"
" frame\n");
return DWARF_CB_ABORT;
}
@@ -269,41 +282,54 @@ static int frame_cb(Dwfl_Frame *frame, void *userdata)
NULL);
procname = dwfl_module_addrname(module, pc_adjusted);
line = dwfl_module_getsrc(module, pc_adjusted);
if (procname && modname) {
g_string_append_printf(*bt, "#%u %s() - [%s]\n",
frame_counter++, procname, modname);
nc_string_append_printf(*bt, "#%u %s() - [%s]",
frame_counter++, procname, modname);
} else if (modname) {
g_string_append_printf(*bt, "#%u ??? - [%s]\n",
frame_counter++, modname);
nc_string_append_printf(*bt, "#%u ??? - [%s]",
frame_counter++, modname);
} else {
// TODO: decide on "no symbol" representation
g_string_append_printf(*bt, "#%u (no symbols)\n",
frame_counter++);
nc_string_append_printf(*bt, "#%u (no symbols)",
frame_counter++);
}
if (line) {
const char *src;
int lineno, linecol;
src = dwfl_lineinfo(line, &pc_adjusted, &lineno, &linecol, NULL, NULL);
if (src) {
nc_string_append_printf(*bt, " - %s:%i", src, lineno);
}
}
nc_string_append_printf(*bt, "\n");
return DWARF_CB_OK;
}
static int thread_cb(Dwfl_Thread *thread, void *userdata)
{
int ret;
GString **bt = (GString **)userdata;
nc_string **bt = (nc_string **)userdata;
pid_t tid;
tid = dwfl_thread_tid(thread);
g_string_append_printf(*bt, "\nBacktrace (TID %u):\n",
(unsigned int)tid);
nc_string_append_printf(*bt, "\nBacktrace (TID %u):\n",
(unsigned int)tid);
ret = dwfl_thread_getframes(thread, frame_cb, userdata);
switch (ret) {
case -1:
errorstr = g_strdup_printf("Error while iterating"
" through frames for thread"
" %u: %s\n",
(unsigned int)tid,
dwfl_errmsg(-1));
if (asprintf(&errorstr, "Error while iterating"
" through frames for thread"
" %u: %s\n",
(unsigned int)tid,
dwfl_errmsg(-1)) < 0) {
errorstr = NULL;
}
return DWARF_CB_ABORT;
case DWARF_CB_ABORT:
/* already set the error string in frame_cb */
@@ -319,14 +345,14 @@ static int thread_cb(Dwfl_Thread *thread, void *userdata)
frame_counter = 0;
#if 0
g_string_append_printf(*bt, "\nRegisters (TID %u):\nTODO\n", current,
(unsigned int)tid);
nc_string_append_printf(*bt, "\nRegisters (TID %u):\nTODO\n", current,
(unsigned int)tid);
#endif
return DWARF_CB_OK;
}
static bool send_data(GString **backtrace, uint32_t severity, char *class)
static bool send_data(nc_string **backtrace, uint32_t severity, char *class)
{
struct telem_ref *handle = NULL;
int ret;
@@ -360,15 +386,15 @@ fail:
* which must be initialized prior to calling this function. The callback
* function for processing each core thread is passed as the second argument to
* dwfl_getthreads(). The backtrace argument is the address of a pointer to a
* GString object declared by the caller which stores the backtrace data as a
* nc_string object declared by the caller which stores the backtrace data as a
* string.
*/
static int process_corefile(GString **backtrace)
static int process_corefile(nc_string **backtrace)
{
if (*backtrace) {
g_string_free(*backtrace, TRUE);
nc_string_free(*backtrace);
}
*backtrace = g_string_new(NULL);
*backtrace = nc_string_dup("");
if (dwfl_getthreads(d_core, thread_cb, backtrace) != DWARF_CB_OK) {
/* When errors occur during the unwinding, we reach this point.
@@ -378,8 +404,8 @@ static int process_corefile(GString **backtrace)
*/
if (errorstr != NULL) {
telem_log(LOG_ERR, "%s", errorstr);
g_string_append_printf(header, "Error: %s", errorstr);
g_string_prepend(*backtrace, header->str);
nc_string_append_printf(header, "Error: %s", errorstr);
nc_string_prepend(*backtrace, header->str);
send_data(backtrace, error_severity, error_class);
}
goto fail;
@@ -390,7 +416,7 @@ fail:
return -1;
}
static bool in_clr_build(gchar *fullpath)
static bool in_clr_build(char *fullpath)
{
// Global override for privacy filters
if (access(TM_PRIVACY_FILTERS_OVERRIDE, F_OK) == 0) {
@@ -401,15 +427,15 @@ static bool in_clr_build(gchar *fullpath)
* The build environment for Clear Linux packages is set up by 'mock',
* and the chroot in which rpmbuild builds the packages has this prefix.
*/
if (g_regex_match_simple("^[!/]builddir[!/]build[!/]BUILD[!/]",
fullpath, 0, 0) == TRUE) {
if ((strstr(fullpath, "/builddir/build/BUILD/")) ||
(strstr(fullpath, "!builddir!build!BUILD!"))) {
return true;
}
return false;
}
static bool is_banned_path(gchar *fullpath)
static bool is_banned_path(char *fullpath)
{
// Global override for privacy filters
if (access(TM_PRIVACY_FILTERS_OVERRIDE, F_OK) == 0) {
@@ -417,52 +443,55 @@ static bool is_banned_path(gchar *fullpath)
}
// Anything outside of /usr/, or in /usr/local/, we consider third-party
if (g_regex_match_simple("^[!/]usr[!/]", fullpath, 0, 0) == FALSE) {
if ((strncmp(fullpath, "/usr/", 5) != 0) &&
(strncmp(fullpath, "!usr!", 5) != 0)) {
return true;
} else if (g_regex_match_simple("^[!/]usr[!/]local[!/]", fullpath,
0, 0) == TRUE) {
}
if ((strncmp(fullpath, "/usr/local/", 11) == 0) ||
(strncmp(fullpath, "!usr!local!", 11) == 0)) {
return true;
}
return false;
}
static gchar *config_file = NULL;
static gchar *core_file = NULL;
static gchar *proc_path = NULL;
static gint signal_num = -1;
static gboolean version_p = FALSE;
static gboolean verbose = FALSE;
static char *config_file = NULL;
static char *core_file = NULL;
static char *proc_path = NULL;
static long int signal_num = -1;
static bool verbose = false;
static GOptionEntry options[] = {
{ "config-file", 'f', 0, G_OPTION_ARG_FILENAME, &config_file,
"Path to configuration file (not implemented yet)", NULL },
{ "core-file", 'c', 0, G_OPTION_ARG_FILENAME, &core_file,
"Path to core file to process", NULL },
{ "process-name", 'p', 0, G_OPTION_ARG_STRING, &proc_name,
"Name of process for crash report (required)", NULL },
{ "process-path", 'E', 0, G_OPTION_ARG_STRING, &proc_path,
"Absolute path of crashed process, with ! or / delimiters", NULL },
{ "signal", 's', 0, G_OPTION_ARG_INT, &signal_num,
"Signal number that crashed the process", NULL },
{ "version", 'V', 0, G_OPTION_ARG_NONE, &version_p,
"Print the program version", NULL },
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
"Print the crash probe payload to stdout", NULL },
{ NULL }
static const struct option prog_opts[] = {
{ "help", no_argument, 0, 'h' },
{ "config-file", required_argument, 0, 'f' },
{ "core-file", required_argument, 0, 'c' },
{ "process-name", required_argument, 0, 'p' },
{ "process-path", required_argument, 0, 'E' },
{ "signal", required_argument, 0, 's' },
{ "version", no_argument, 0, 'V' },
{ "verbose", no_argument, 0, 'v' },
{ 0, 0, 0, 0 }
};
static void free_glib_strings(void)
static void print_help(void)
{
if (core_file) {
g_free(core_file);
}
if (proc_name) {
g_free(proc_name);
}
if (proc_path) {
g_free(proc_path);
}
printf("Usage:\n");
printf(" crashprobe [OPTIONS] - collect data from core files\n");
printf("\n");
printf("Help Options:\n");
printf(" -h, --help Show help options\n");
printf("\n");
printf("Application Options:\n");
printf(" -f, --config-file Path to configuration file (not implemented yet)\n");
printf(" -c, --core-file Path to core file to process\n");
printf(" -p, --process-name Name of process for crash report (required)\n");
printf(" -E, --process-path Absolute path of crashed process, with ! or / delimiters\n");
printf(" -s, --signal Signal number that crashed the process\n");
printf(" -V, --version Print the program version\n");
printf(" -v, --verbose Print the crash payload to stdout\n");
printf("\n");
}
int main(int argc, char **argv)
@@ -470,9 +499,7 @@ int main(int argc, char **argv)
Elf *e_core = NULL;
int ret = EXIT_FAILURE;
int core_fd = STDIN_FILENO;
GString *backtrace = NULL;
GError *error = NULL;
GOptionContext *context;
nc_string *backtrace = NULL;
if (fcntl(STDERR_FILENO, F_GETFL) < 0) {
// redirect stderr to avoid bad things to happen with
@@ -488,28 +515,58 @@ int main(int argc, char **argv)
drop_privs();
context = g_option_context_new("- collect data from core files");
g_option_context_add_main_entries(context, options, NULL);
g_option_context_set_translate_func(context, NULL, NULL, NULL);
if (!g_option_context_parse(context, &argc, &argv, &error)) {
g_print("Failed to parse options: %s\n", error->message);
exit(EXIT_FAILURE);
}
int opt;
if (version_p) {
g_print(PACKAGE_VERSION "\n");
exit(EXIT_SUCCESS);
while ((opt = getopt_long(argc, argv, "hf:c:p:E:s:Vv", prog_opts, NULL)) != -1) {
switch (opt) {
case 'h':
print_help();
goto success;
case 'V':
printf(PACKAGE_VERSION "\n");
goto success;
case 'f':
config_file = strdup(optarg);
break;
case 'c':
core_file = strdup(optarg);
break;
case 'p':
proc_name = strdup(optarg);
break;
case 'E':
proc_path = strdup(optarg);
break;
case 's':
errno = 0;
char *endptr = NULL;
signal_num = strtol(optarg, &endptr, 10);
if (errno != 0) {
telem_perror("Failed to convert signal number");
goto fail;
}
if (endptr && *endptr != '\0') {
telem_log(LOG_ERR, "Invalid signal number. Must be an integer\n");
goto fail;
}
break;
case 'v':
verbose = true;
break;
}
}
if (!proc_name) {
g_print("Missing required -p option. See --help output\n");
printf("Missing required -p option. See --help output\n");
exit(EXIT_FAILURE);
}
if (proc_path && in_clr_build(proc_path)) {
telem_log(LOG_NOTICE, "Ignoring core (from mock build)\n");
backtrace = g_string_new("Crash from Clear package build\n");
backtrace = nc_string_dup("Crash from Clear package build\n");
if (!send_data(&backtrace, unknown_severity, clr_build_class)) {
goto fail;
@@ -520,7 +577,7 @@ int main(int argc, char **argv)
if (proc_path && is_banned_path(proc_path)) {
telem_log(LOG_NOTICE, "Ignoring core (third-party binary)\n");
backtrace = g_string_new("Crash from third party\n");
backtrace = nc_string_dup("Crash from third party\n");
if (!send_data(&backtrace, unknown_severity, unknown_class)) {
goto fail;
@@ -554,8 +611,8 @@ int main(int argc, char **argv)
goto fail;
}
} else {
g_print("Cannot process core file. Use the -c option,"
" or pass the core file on stdin.\n");
printf("Cannot process core file. Use the -c option,"
" or pass the core file on stdin.\n");
goto fail;
}
}
@@ -566,13 +623,12 @@ int main(int argc, char **argv)
goto fail;
}
header = g_string_new(NULL);
g_string_printf(header, "Process: %s\nPID: %u\n",
proc_path ? replace_exclamations(proc_path) : proc_name,
(unsigned int)core_for_pid);
header = nc_string_dup_printf("Process: %s\nPID: %u\n",
proc_path ? replace_exclamations(proc_path) : proc_name,
(unsigned int)core_for_pid);
if (signal_num >= 0) {
g_string_append_printf(header, "Signal: %d\n", signal_num);
nc_string_append_printf(header, "Signal: %ld\n", signal_num);
}
if (process_corefile(&backtrace) < 0) {
@@ -596,7 +652,7 @@ int main(int argc, char **argv)
}
}
g_string_prepend(backtrace, header->str);
nc_string_prepend(backtrace, header->str);
if (!send_data(&backtrace, default_severity, clr_class)) {
goto fail;
@@ -611,22 +667,20 @@ success:
ret = EXIT_SUCCESS;
fail:
free_glib_strings();
if (context) {
g_option_context_free(context);
}
free(core_file);
free(proc_name);
free(proc_path);
if (header) {
g_string_free(header, TRUE);
nc_string_free(header);
}
if (backtrace) {
g_string_free(backtrace, TRUE);
nc_string_free(backtrace);
}
if (errorstr) {
g_free(errorstr);
free(errorstr);
}
if (d_core) {
+46 -41
View File
@@ -15,6 +15,7 @@
*/
#define _GNU_SOURCE
#include <getopt.h>
#include <poll.h>
#include <stdbool.h>
#include <stdio.h>
@@ -22,8 +23,6 @@
#include <string.h>
#include <unistd.h>
#include <glib.h>
/* Certain static analysis tools do not understand GCC's __INCLUDE_LEVEL__
* macro; the conditional definition below is used to fix the build with
* systemd's _sd-common.h, included by the public systemd headers, which rely on
@@ -39,10 +38,10 @@
#include "config.h"
#include "log.h"
#include "telemetry.h"
#include "nica/nc-string.h"
#define BOOT_ID_LEN 33
static GString *payload = NULL;
static nc_string *payload = NULL;
static uint32_t severity = 2;
static uint32_t payload_version = 1;
static char error_class[30] = "org.clearlinux/journal/error";
@@ -61,12 +60,11 @@ static inline void tm_journal_match_err(int ret)
static void add_to_payload(const void *data, size_t length)
{
if (payload != NULL) {
g_string_append_printf(payload, "%.*s\n", (int)length,
(char *)data);
nc_string_append_printf(payload, "%.*s\n", (int)length,
(char *)data);
} else {
payload = g_string_new(NULL);
g_string_printf(payload, "%.*s\n", (int)length,
(char *)data);
payload = nc_string_dup_printf("%.*s\n", (int)length,
(char *)data);
}
}
@@ -82,7 +80,8 @@ static bool send_data(char *class)
goto fail;
}
gchar *payload_str = g_string_free(payload, FALSE);
char *payload_str = strdup(payload->str);
nc_string_free(payload);
payload = NULL;
if ((ret = tm_set_payload(handle, (char *)payload_str)) < 0) {
@@ -299,41 +298,51 @@ static bool process_journal(void)
}
}
static gchar *config_file = NULL;
static gboolean version_p = FALSE;
static char *config_file = NULL;
static GOptionEntry options[] = {
{ "config-file", 'f', 0, G_OPTION_ARG_FILENAME, &config_file,
"Path to configuration file (not implemented yet)", NULL },
{ "version", 'V', 0, G_OPTION_ARG_NONE, &version_p,
"Print the program version", NULL },
{ NULL }
static const struct option prog_opts[] = {
{ "help", no_argument, 0, 'h' },
{ "config-file", required_argument, 0, 'f' },
{ "version", no_argument, 0, 'V' },
{ 0, 0, 0, 0 }
};
static void free_glib_strings(void)
static void print_help(void)
{
if (config_file) {
g_free(config_file);
}
printf("Usage:\n");
printf(" journalprobe [OPTIONS] - collect data from systemd journal\n");
printf("\n");
printf("Help Options:\n");
printf(" -h, --help Show help options\n");
printf("\n");
printf("Application Options:\n");
printf(" -f, --config-file Path to configuration file (not implemented yet)\n");
printf(" -V, --version Print the program version\n");
printf("\n");
}
static void free_strings(void)
{
free(config_file);
}
int main(int argc, char **argv)
{
int ret = EXIT_FAILURE;
GError *error = NULL;
GOptionContext *context;
int opt;
context = g_option_context_new("- collect data from systemd journal");
g_option_context_add_main_entries(context, options, NULL);
g_option_context_set_translate_func(context, NULL, NULL, NULL);
if (!g_option_context_parse(context, &argc, &argv, &error)) {
g_print("Failed to parse options: %s\n", error->message);
goto fail;
}
if (version_p) {
g_print(PACKAGE_VERSION "\n");
goto success;
while ((opt = getopt_long(argc, argv, "hf:V", prog_opts, NULL)) != -1) {
switch (opt) {
case 'h':
print_help();
goto success;
case 'V':
printf(PACKAGE_VERSION "\n");
goto success;
case 'f':
config_file = strdup(optarg);
break;
}
}
if (!process_journal()) {
@@ -343,18 +352,14 @@ int main(int argc, char **argv)
success:
ret = EXIT_SUCCESS;
fail:
free_glib_strings();
free_strings();
if (journal) {
sd_journal_close(journal);
}
if (context) {
g_option_context_free(context);
}
if (payload) {
g_string_free(payload, TRUE);
nc_string_free(payload);
}
return ret;
+3 -1
View File
@@ -7,6 +7,7 @@
#include <errno.h>
#include <unistd.h>
#include <malloc.h>
#include <signal.h>
#include "log.h"
#include "oops_parser.h"
@@ -50,8 +51,9 @@ int main(void)
buflen = (size_t)log_size;
if (loopcount++ > 0 && buflen > MAX_BUF)
if (loopcount++ > 0 && buflen > MAX_BUF) {
buflen = MAX_BUF;
}
// Gets the contents of the kernel ring buffer
bufp = (char *)calloc(buflen, sizeof(char));
-1
View File
@@ -22,7 +22,6 @@
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <glib.h>
#include <sys/stat.h>
#include "log.h"
+5
View File
@@ -45,6 +45,7 @@ endif
%C%_crashprobe_SOURCES = \
%D%/crash_probe.c \
src/nica/nc-string.c \
%D%/probe.h
%C%_crashprobe_CFLAGS = \
$(AM_CFLAGS) \
@@ -69,6 +70,7 @@ endif
%C%_pstoreprobe_SOURCES = \
%D%/pstore_probe.c \
src/nica/nc-string.c \
%D%/oops_parser.c
%C%_pstoreprobe_CFLAGS = \
$(AM_CFLAGS) \
@@ -92,6 +94,7 @@ endif
%D%/klog_scanner.c \
%D%/klog_scanner.h \
%D%/oops_parser.h \
src/nica/nc-string.c \
%D%/oops_parser.c
%C%_klogscanner_CFLAGS = \
$(AM_CFLAGS) \
@@ -122,6 +125,7 @@ endif
%C%_oopsprobe_SOURCES = \
%D%/oops_probe.c \
%D%/oops_parser.c \
src/nica/nc-string.c \
%D%/probe.h
%C%_oopsprobe_CFLAGS = \
$(AM_CFLAGS) \
@@ -146,6 +150,7 @@ bin_PROGRAMS += \
%D%/journalprobe
%C%_journalprobe_SOURCES = \
src/nica/nc-string.c \
%D%/journal.c
%C%_journalprobe_CFLAGS = \
$(AM_CFLAGS) \
+21 -22
View File
@@ -739,18 +739,18 @@ void parse_registers(char *line)
}
void append_registers_to_bt(GString **backtrace)
void append_registers_to_bt(nc_string **backtrace)
{
struct reg_s *reg_entry = reg_head;
while (reg_entry != NULL) {
// Global override for privacy filters
if (access(TM_PRIVACY_FILTERS_OVERRIDE, F_OK) == 0) {
g_string_append_printf(*backtrace, "Register %s: %" PRIx64 "\n", reg_entry->reg_name,
reg_entry->reg_value);
nc_string_append_printf(*backtrace, "Register %s: %" PRIx64 "\n", reg_entry->reg_name,
reg_entry->reg_value);
} else {
g_string_append_printf(*backtrace, "Register %s: %s\n", reg_entry->reg_name,
reg_entry->reg_value ? "Non-zero" : "Zero");
nc_string_append_printf(*backtrace, "Register %s: %s\n", reg_entry->reg_name,
reg_entry->reg_value ? "Non-zero" : "Zero");
}
reg_entry = reg_entry->next;
}
@@ -762,12 +762,12 @@ void append_registers_to_bt(GString **backtrace)
}
}
GString *parse_backtrace(struct oops_log_msg *msg)
nc_string *parse_backtrace(struct oops_log_msg *msg)
{
struct stack_frame *head = NULL, *tail = NULL, *elem = NULL;
//int in_stack_dump = 0;
char *line = NULL;
GString *backtrace = NULL;
nc_string *backtrace = NULL;
int frame_counter = 1;
char *modules = NULL, *kernel_version = NULL, *tainted = NULL;
// Since lines are processed from last to first, the stack trace lines
@@ -805,23 +805,23 @@ GString *parse_backtrace(struct oops_log_msg *msg)
parse_registers(line);
}
backtrace = g_string_new(NULL);
backtrace = nc_string_dup("");
if (kernel_version) {
g_string_append_printf(backtrace, "Kernel Version : %s\n", kernel_version);
nc_string_append_printf(backtrace, "Kernel Version : %s\n", kernel_version);
free(kernel_version);
}
if (tainted) {
g_string_append_printf(backtrace, "Tainted : %s\n", tainted);
nc_string_append_printf(backtrace, "Tainted : %s\n", tainted);
free(tainted);
}
if (modules) {
g_string_append_printf(backtrace, "Modules : %s\n", modules);
nc_string_append_printf(backtrace, "Modules : %s\n", modules);
}
if (head) {
g_string_append_printf(backtrace, "Backtrace :\n");
nc_string_append_printf(backtrace, "Backtrace :\n");
}
if (reg_head) {
@@ -829,24 +829,24 @@ GString *parse_backtrace(struct oops_log_msg *msg)
}
for (elem = head; elem != NULL; elem = elem->next, frame_counter++) {
g_string_append_printf(backtrace, "#%d %s - [%s]\n", frame_counter,
elem->function ? elem->function : "???",
elem->module);
nc_string_append_printf(backtrace, "#%d %s - [%s]\n", frame_counter,
elem->function ? elem->function : "???",
elem->module);
}
stack_frame_free(&head);
return backtrace;
}
GString *parse_payload(struct oops_log_msg *msg)
nc_string *parse_payload(struct oops_log_msg *msg)
{
GString *payload, *backtrace;
nc_string *payload, *backtrace;
payload = g_string_new("Crash Report:\n");
g_string_append_printf(payload, "Reason: %s\n", msg->lines[0]);
payload = nc_string_dup("Crash Report:\n");
nc_string_append_printf(payload, "Reason: %s\n", msg->lines[0]);
backtrace = parse_backtrace(msg);
g_string_append (payload, backtrace->str);
g_string_free(backtrace, true);
nc_string_cat(payload, backtrace->str);
nc_string_free(backtrace);
return payload;
}
@@ -859,4 +859,3 @@ GString *parse_payload(struct oops_log_msg *msg)
*/
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
+2 -3
View File
@@ -17,7 +17,7 @@
#define MAX_LINES 100
#include <glib.h>
#include "nica/nc-string.h"
#include <stdbool.h>
#include <regex.h>
@@ -63,7 +63,7 @@ void oops_parser_init(oops_handler_t handler);
void parse_single_line(char *line, size_t size);
/* Parses a payload from an oops msg*/
GString *parse_payload(struct oops_log_msg *msg);
nc_string *parse_payload(struct oops_log_msg *msg);
/* Given an entire oops log, verifies that the log is an oops log and
* extracts the lines into an oops struct.
@@ -74,4 +74,3 @@ bool handle_entire_oops(char *buf, long size, struct oops_log_msg *msg);
void oops_msg_cleanup(struct oops_log_msg *msg);
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
+4 -4
View File
@@ -17,11 +17,9 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <glib.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <glib.h>
#include <sys/inotify.h>
#include <poll.h>
@@ -29,6 +27,8 @@
#include "log.h"
#include "telemetry.h"
#include "nica/nc-string.h"
char *oops_dir_path = KERNELOOPSDIR;
static uint32_t version = 1;
@@ -68,7 +68,7 @@ void handle_oops_file(const char *fname)
char *filename = NULL, *contents = NULL;
long sz;
size_t size, bytes_read;
GString *payload;
nc_string *payload;
ret = asprintf(&filename, "%s/%s", oops_dir_path, fname);
if (ret == -1) {
@@ -138,7 +138,7 @@ void handle_oops_file(const char *fname)
oops_msg_cleanup(&oops_msg);
send_data(payload->str, (char *)oops_msg.pattern->classification, (uint32_t)oops_msg.pattern->severity);
g_string_free(payload, true);
nc_string_free(payload);
} else {
/* File does no contain an oops! */
telem_log(LOG_ERR, "Did not find an oops in the oops directort\n");
-1
View File
@@ -22,5 +22,4 @@
*/
#define TM_PRIVACY_FILTERS_OVERRIDE "/etc/telemetrics/opt-in-no-privacy-filters"
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
+9 -6
View File
@@ -12,7 +12,7 @@
* A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
@@ -61,7 +61,7 @@ static bool send_data(char *backtrace, char *class, uint32_t severity)
void handle_complete_oops_message(struct oops_log_msg *msg)
{
GString *payload;
nc_string *payload;
#ifdef DEBUG
for (int i = 0; i < msg->length; i++) {
@@ -74,7 +74,7 @@ void handle_complete_oops_message(struct oops_log_msg *msg)
printf("Payload Parsed :%s\n", payload->str);
#endif
send_data(payload->str, (char *)msg->pattern->classification, (uint32_t)msg->pattern->severity);
g_string_free(payload, true);
nc_string_free(payload);
}
void handle_crash_dump(char *dump, size_t size)
@@ -100,7 +100,7 @@ void handle_crash_dump(char *dump, size_t size)
char *read_contents(char *filename, size_t *bytes)
{
gchar *dump_file;
char *dump_file = NULL;
FILE *fp = NULL;
char *contents = NULL;
long sz = 0;
@@ -108,7 +108,10 @@ char *read_contents(char *filename, size_t *bytes)
char *hdr_end;
size_t hdr_len;
dump_file = g_strconcat(pstore_dump_path, "/", filename, NULL);
if (asprintf(&dump_file, "%s/%s", pstore_dump_path, filename) < 0) {
goto end;
}
fp = fopen(dump_file, "r");
if (fp == NULL) {
telem_log(LOG_ERR, "Failed to open pstore dump file %s:%s\n", dump_file, strerror(errno));
@@ -170,7 +173,7 @@ end:
fclose(fp);
}
g_free(dump_file);
free(dump_file);
return contents;
}
+102 -68
View File
@@ -15,6 +15,8 @@
*/
#define _GNU_SOURCE
#include <ctype.h>
#include <getopt.h>
#include <poll.h>
#include <stdbool.h>
#include <stdio.h>
@@ -22,40 +24,52 @@
#include <string.h>
#include <unistd.h>
#include <glib.h>
#include <string.h>
#include <stdint.h>
#include "config.h"
#include "log.h"
#include "common.h"
#include "telemetry.h"
static gchar *config_file = NULL;
static gboolean version_p = FALSE;
static guint severity = 1;
static gchar *opt_class = NULL;
static gchar *opt_payload = NULL;
static guint payload_version = 1;
static gchar *opt_payload_file = NULL;
static char *config_file = NULL;
static uint32_t severity = 1;
static char *opt_class = NULL;
static char *opt_payload = NULL;
static uint32_t payload_version = 1;
static char *opt_payload_file = NULL;
static GOptionEntry options[] = {
{ "config-file", 'f', 0, G_OPTION_ARG_FILENAME, &config_file,
"Path to configuration file (not implemented yet)", NULL },
{ "version", 'V', 0, G_OPTION_ARG_NONE, &version_p,
"Print the program version", NULL },
{ "severity", 's', 0, G_OPTION_ARG_INT, &severity,
"Severity level (1-4) - (default 1)", NULL },
{ "class", 'c', 0, G_OPTION_ARG_STRING, &opt_class,
"Classification level_1/level_2/level_3", NULL },
{ "payload", 'p', 0, G_OPTION_ARG_STRING, &opt_payload,
"Record body (max size = 8k)", NULL },
{ "payload-file", 'P', 0, G_OPTION_ARG_STRING, &opt_payload_file,
"File to read payload from", NULL },
{ "record-version", 'R', 0, G_OPTION_ARG_INT, &payload_version,
"Version number for format of payload (default 1)", NULL },
{ NULL }
static const struct option prog_opts[] = {
{ "help", no_argument, 0, 'h' },
{ "config-file", required_argument, 0, 'f' },
{ "version", no_argument, 0, 'V' },
{ "severity", required_argument, 0, 's' },
{ "class", required_argument, 0, 'c' },
{ "payload", required_argument, 0, 'p' },
{ "payload-file", required_argument, 0, 'P' },
{ "record-version", required_argument, 0, 'R' },
{ 0, 0, 0, 0 }
};
static void print_help(void)
{
printf("Usage:\n");
printf(" telem-record-gen [OPTIONS] - create and send a custom telemetry record\n");
printf("\n");
printf("Help Options:\n");
printf(" -h, --help Show help options\n");
printf("\n");
printf("Application Options:\n");
printf(" -f, --config-file Path to configuration file (not implemented yet)\n");
printf(" -V, --version Print the program version\n");
printf(" -s, --severity Severity level (1-4) - (default 1)\n");
printf(" -c, --class Classification level_1/level_2/level_3\n");
printf(" -p, --payload Record body (max size = 8k)\n");
printf(" -P, --payload-file File to read payload from\n");
printf(" -R, --record-version Version number for format of payload (default 1)\n");
printf("\n");
}
const unsigned int count_chars(const char *check, const char character)
{
unsigned int count = 0U;
@@ -70,44 +84,67 @@ const unsigned int count_chars(const char *check, const char character)
return count;
}
static void free_glib_strings(void)
{
if (config_file) {
g_free(config_file);
}
if (opt_class) {
g_free(opt_class);
}
if (opt_payload) {
g_free(opt_payload);
}
}
int parse_options(int argc, char **argv)
{
int ret = 0;
GError *error = NULL;
GOptionContext *context;
char *endptr = NULL;
long unsigned int tmp = 0;
context = g_option_context_new(
"- create and send a custom telemetry record\n");
g_option_context_add_main_entries(context, options, NULL);
g_option_context_set_translate_func(context, NULL, NULL, NULL);
int opt;
while ((opt = getopt_long(argc, argv, "hc:Vs:c:p:P:R:", prog_opts, NULL)) != -1) {
switch (opt) {
case 'h':
print_help();
exit(EXIT_SUCCESS);
case 'V':
printf(PACKAGE_VERSION "\n");
exit(EXIT_SUCCESS);
case 's':
errno = 0;
if (!g_option_context_parse(context, &argc, &argv, &error)) {
g_print("Failed to parse options: %s\n", error->message);
goto fail;
tmp = strtoul(optarg, &endptr, 10);
if (errno != 0) {
telem_perror("Failed to convert severity number");
goto fail;
}
if (endptr && *endptr != '\0') {
telem_log(LOG_ERR, "Invalid severity number. Must be an integer\n");
goto fail;
}
severity = (uint32_t)tmp;
break;
case 'c':
opt_class = strdup(optarg);
break;
case 'p':
opt_payload = strdup(optarg);
break;
case 'P':
opt_payload_file = strdup(optarg);
break;
case 'R':
errno = 0;
tmp = strtoul(optarg, &endptr, 10);
if (errno != 0) {
telem_perror("Failed to convert record-version number");
goto fail;
}
if (endptr && *endptr != '\0') {
telem_log(LOG_ERR, "Invalid record-version number. Must be an integer\n");
goto fail;
}
payload_version = (uint32_t)tmp;
break;
}
}
ret = 1;
fail:
if (context) {
g_option_context_free(context);
}
return ret;
}
@@ -130,10 +167,12 @@ int validate_opts(void)
return ret;
}
if (!g_str_is_ascii(opt_class)) {
fprintf(stderr, "Error: Non-ascii characters detected "
"in classification - aborting\n");
return ret;
for (int c = 0; c < strlen(opt_class); c++) {
if (isascii(opt_class[c]) == 0) {
fprintf(stderr, "Error: Non-ascii characters detected "
"in classification - aborting\n");
return ret;
}
}
if (count_chars(opt_class, '/') != 2) {
@@ -155,7 +194,7 @@ int allocate_payload_buffer(char **payload)
{
int ret = 0;
*payload = (char *)malloc(sizeof(gchar) * MAX_PAYLOAD_SIZE);
*payload = (char *)malloc(MAX_PAYLOAD_SIZE);
if (*payload == NULL) {
goto out1;
@@ -182,7 +221,7 @@ int get_payload_from_file(char **payload)
goto out;
}
bytes_in = fread(*payload, sizeof(gchar),
bytes_in = fread(*payload, 1,
MAX_PAYLOAD_SIZE - 1, fp);
/* if fread fails */
@@ -215,7 +254,7 @@ void get_payload_from_stdin(char **payload)
size_t bytes_in = 0;
int c;
bytes_in = fread(*payload, sizeof(gchar), MAX_PAYLOAD_SIZE - 1, stdin);
bytes_in = fread(*payload, 1, MAX_PAYLOAD_SIZE - 1, stdin);
if (bytes_in == MAX_PAYLOAD_SIZE - 1) {
/* Throw away the rest of stdin */
@@ -292,11 +331,6 @@ int main(int argc, char **argv)
goto fail;
}
if (version_p) {
g_print(PACKAGE_VERSION "\n");
goto success;
}
if (!validate_opts()) {
goto fail;
}
@@ -309,13 +343,13 @@ int main(int argc, char **argv)
goto fail;
}
success:
ret = EXIT_SUCCESS;
fail:
free_glib_strings();
free(config_file);
free(opt_class);
free(opt_payload);
return ret;
}
/* vi: set ts=8 sw=8 sts=4 et tw=80 cino=(0: */
+4 -4
View File
@@ -511,11 +511,11 @@ bool post_record_http(char *headers[], char *body, bool spool)
if (res) {
size_t len = strlen(errorbuf);
if (len) {
telem_log(LOG_ERR, "Failed sending record: %s%s", errorbuf,
((errorbuf[len - 1] != '\n') ? "\n" : ""));
telem_log(LOG_ERR, "Failed sending record: %s%s", errorbuf,
((errorbuf[len - 1] != '\n') ? "\n" : ""));
} else {
telem_log(LOG_ERR, "Failed sending record: %s\n",
curl_easy_strerror(res));
telem_log(LOG_ERR, "Failed sending record: %s\n",
curl_easy_strerror(res));
}
} else if (http_response != 201 && http_response != 200) {
/* 201 means the record was successfully created
+3 -3
View File
@@ -15,7 +15,6 @@
*/
#define _GNU_SOURCE
#include <glib.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
@@ -29,6 +28,7 @@
#include <sys/un.h>
#include <limits.h>
#include <inttypes.h>
#include <ctype.h>
#include "common.h"
#include "configuration.h"
@@ -806,8 +806,8 @@ int payload_is_ascii(char *payload, size_t len)
int ret = 0;
for (i = 0; i < len; i++) {
if (!g_ascii_isprint((gchar)payload[i]) &&
!g_ascii_isspace((gchar)payload[i])) {
if (!isprint(payload[i]) &&
!isspace(payload[i])) {
ret = -EINVAL;
break;
}
+2 -2
View File
@@ -50,7 +50,7 @@ START_TEST(check_read_valid_config)
ck_assert_str_eq(config.strValues[CONF_CAINFO], "/tmp/cacert.crt");
ck_assert_str_eq(config.strValues[CONF_TIDHEADER],
"X-Telemetry-TID: 6907c830-eed9-4ce9-81ae-76daf8d88f0f");
ck_assert(config.boolValues[CONF_DAEMON_RECYCLING_ENABLED] == true);
ck_assert(config.boolValues[CONF_DAEMON_RECYCLING_ENABLED] == true);
}
END_TEST
@@ -76,7 +76,7 @@ START_TEST(check_config_initialised)
ck_assert_str_eq(get_cainfo_config(), "/tmp/cacert.crt");
ck_assert_str_eq(get_tidheader_config(),
"X-Telemetry-TID: 6907c830-eed9-4ce9-81ae-76daf8d88f0f");
ck_assert(daemon_recycling_enabled_config() == true);
ck_assert(daemon_recycling_enabled_config() == true);
}
END_TEST
+18 -18
View File
@@ -22,16 +22,16 @@
#include <errno.h>
#include <stdbool.h>
#include <string.h>
#include <glib.h>
#include "nica/nc-string.h"
#include "log.h"
#include "read_oopsfile.h"
#include "src/probes/klog_scanner.h"
#include "src/probes/oops_parser.h"
char reason[1024];
GString *bt;
GString *pl;
nc_string *bt;
nc_string *pl;
void callback_func(struct oops_log_msg *msg)
{
@@ -119,7 +119,7 @@ START_TEST(watchdog_payload)
ck_assert(strstr(pl->str, "#20 ? clockevents_register_device"));
ck_assert(strstr(pl->str, "#21 start_secondary"));
g_string_free(pl, true);
nc_string_free(pl);
}
END_TEST
@@ -144,7 +144,7 @@ START_TEST(alsa_bug_payload)
ck_assert(strstr(pl->str, "#2 ? vsnprintf"));
ck_assert(strstr(pl->str, "#3 ? _spin_unlock_irqrestore"));
ck_assert(strstr(pl->str, "#10 start_kernel"));
g_string_free(pl, true);
nc_string_free(pl);
}
END_TEST
@@ -182,7 +182,7 @@ START_TEST(warning_payload)
ck_assert(strstr(pl->str, "#12 ? SyS_ioctl"));
ck_assert(strstr(pl->str, "#13 ? entry_SYSCALL_64_fastpath"));
g_string_free(pl, true);
nc_string_free(pl);
}
END_TEST
@@ -222,7 +222,7 @@ START_TEST(warn_on_payload)
ck_assert(strstr(pl->str, "#16 cpu_startup_entry"));
ck_assert(strstr(pl->str, "#17 start_secondary"));
g_string_free(pl, true);
nc_string_free(pl);
}
END_TEST
@@ -300,7 +300,7 @@ START_TEST(sysctl2_payload)
ck_assert(strstr(pl->str, "#13 ? copy_net_ns"));
ck_assert(strstr(pl->str, "#14 ? create_new_namespaces"));
g_string_free(pl, true);
nc_string_free(pl);
}
END_TEST
@@ -337,7 +337,7 @@ START_TEST(softlockup_payload)
ck_assert(strstr(pl->str, "#12 SyS_fgetxattr"));
ck_assert(strstr(pl->str, "#13 system_call_fastpath"));
g_string_free(pl, true);
nc_string_free(pl);
}
END_TEST
@@ -370,7 +370,7 @@ START_TEST(rtnl_payload)
ck_assert(strstr(pl->str, "#12 ? SyS_setsockopt"));
ck_assert(strstr(pl->str, "#13 ? system_call_fastpath"));
g_string_free(pl, true);
nc_string_free(pl);
}
END_TEST
@@ -400,7 +400,7 @@ START_TEST(kernel_null_pointer_payload)
ck_assert(strstr(pl->str, "#6 sys_inotify_rm_watch"));
ck_assert(strstr(pl->str, "#7 system_call_fastpath"));
g_string_free(pl, true);
nc_string_free(pl);
}
END_TEST
@@ -432,7 +432,7 @@ START_TEST(kernel_bug_payload)
ck_assert(strstr(pl->str, "#8 ptregscall_common"));
ck_assert(strstr(pl->str, "#9 sysret_signal"));
g_string_free(pl, true);
nc_string_free(pl);
}
END_TEST
@@ -498,7 +498,7 @@ START_TEST(irq_payload)
ck_assert(strstr(pl->str, "#45 ? kernel_init_freeable"));
ck_assert(strstr(pl->str, "#46 ? do_early_param"));
g_string_free(pl, true);
nc_string_free(pl);
}
END_TEST
@@ -530,7 +530,7 @@ START_TEST(general_protection_fault_payload)
ck_assert(strstr(pl->str, "#7 SyS_pipe"));
ck_assert(strstr(pl->str, "#8 system_call_fastpath"));
g_string_free(pl, true);
nc_string_free(pl);
}
END_TEST
@@ -552,7 +552,7 @@ START_TEST(double_fault_payload)
ck_assert(strstr(pl->str, "Modules : nls_utf8 vfat fat sit tunnel4 ext2 fuse ip6table_filter ip6_tables ebtable_nat"));
ck_assert(strstr(pl->str, "joydev sdhci_pci sdhci usb_storage mmc_core video output [last unloaded: speedstep_lib]"));
g_string_free(pl, true);
nc_string_free(pl);
}
END_TEST
@@ -571,7 +571,7 @@ START_TEST(bad_page_map_payload)
ck_assert(strstr(pl->str, "Kernel Version : 3.12-1-amd64 #1 Debian 3.12.9-1"));
ck_assert(strstr(pl->str, "Tainted : Not tainted"));
g_string_free(pl, true);
nc_string_free(pl);
}
END_TEST
@@ -618,7 +618,7 @@ START_TEST(bug_kernel_handle_payload)
ck_assert(strstr(pl->str, "#22 ? sys_open"));
ck_assert(strstr(pl->str, "#23 ? system_call_fastpath"));
g_string_free(pl, true);
nc_string_free(pl);
}
END_TEST
@@ -665,7 +665,7 @@ START_TEST(bug_kernel_handle_payload_new_format)
ck_assert(strstr(pl->str, "#22 ? sys_open"));
ck_assert(strstr(pl->str, "#23 ? system_call_fastpath"));
g_string_free(pl, true);
nc_string_free(pl);
}
END_TEST
+1
View File
@@ -61,6 +61,7 @@ endif
%D%/read_oopsfile.h \
%D%/read_oopsfile.c \
%D%/check_probes.c \
src/nica/nc-string.c \
src/probes/klog_scanner.c \
src/probes/klog_scanner.h \
src/probes/oops_parser.c \