mirror of
https://github.com/clearlinux/telemetrics-client.git
synced 2026-09-01 11:15:51 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7d3a9d2834 | ||
|
|
0af684e94e | ||
|
|
51374db118 | ||
|
|
dfb40babaa | ||
|
|
b7619e1a1c | ||
|
|
3be37cebb5 | ||
|
|
15a32b6346 | ||
|
|
e0e2aae341 | ||
|
|
4d1f6de3b5 | ||
|
|
f3a641b161 | ||
|
|
9018362ffb | ||
|
|
eedcb88cb7 | ||
|
|
2deeef65ad | ||
|
|
dab667eeea | ||
|
|
787102c4fb | ||
|
|
12d1c82650 | ||
|
|
46d88d6315 | ||
|
|
089183c9e0 | ||
|
|
f354078d3d | ||
|
|
db85aa9a18 | ||
|
|
f5899c7ba6 | ||
|
|
657c8792d5 | ||
|
|
365cfeee9a | ||
|
|
4957452f66 | ||
|
|
e02e22f192 | ||
|
|
60bbe963cb | ||
|
|
1ffc3a00c2 | ||
|
|
60edcdb165 | ||
|
|
bc12e6d5f7 | ||
|
|
e9d29a4e7b | ||
|
|
6295f0f4dc | ||
|
|
4cf3c7e8ac | ||
|
|
d9d957e532 | ||
|
|
f88d646ae1 | ||
|
|
e0619807c9 | ||
|
|
f07c9b168c | ||
|
|
7333bc7968 | ||
|
|
aa4f9e3058 | ||
|
|
6c36253351 | ||
|
|
e78ca8b66f | ||
|
|
a449e6cec1 | ||
|
|
5963f983cd | ||
|
|
c65e58f696 | ||
|
|
1d5b2d0669 | ||
|
|
356be6738f | ||
|
|
e73870b916 | ||
|
|
c7e783f2b1 |
+36
@@ -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
@@ -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:
|
||||
|
||||
@@ -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,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
@@ -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
@@ -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
@@ -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/
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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
@@ -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");
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
noinst_HEADERS += \
|
||||
%D%/macros.h \
|
||||
%D%/nc-string.h
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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:
|
||||
*/
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -22,7 +22,6 @@
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <glib.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
@@ -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
@@ -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: */
|
||||
|
||||
|
||||
@@ -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: */
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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: */
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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 \
|
||||
|
||||
Reference in New Issue
Block a user