Compare commits

..
19 Commits
Author SHA1 Message Date
Patrick McCarty 251b7cfe3b Release v52
- Enable Github Actions for CI test execution.

- Allow runtime configuration of debuginfo URLs by setting the
  CLR_DEBUGINFO_URLS environment variable for the clr_debug_daemon
  service.

- Make the daemon socket path and cache directory configurable at build
  time via the `--with-socket-path` and `--with-cache-dir` options,
  respectively. The default values for those two settings are unchanged.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2021-03-16 01:46:23 +00:00
Josue David Hernandez Gutierrez 97d255f115 Add --with-socket-path=... and --with-cache-dir=... to configure
Signed-off-by: Josue David Hernandez Gutierrez <josue.d.hernandez.gutierrez@intel.com>
2020-01-30 14:11:54 -08:00
Josue David Hernandez Gutierrez 1a36c33e6e Waiting for fuse in testing_fuse test
Signed-off-by: Josue David Hernandez Gutierrez <josue.d.hernandez.gutierrez@intel.com>
2020-01-30 13:35:24 -08:00
Josue David Hernandez Gutierrez b8568a3959 Creating testing binary to test basic behoviour of fuse and daemon binaries
- creating a fake socket check if fuse is sending the request properly to
  the socket service.
- make a request to the server socket while clr_debug_daemon is running
to check that it is responding propertly and also that it is creating cache files
- change makefile.am to compile binaries without add them to the installation process

Signed-off-by: Josue David Hernandez Gutierrez <josue.d.hernandez.gutierrez@intel.com>
2020-01-29 11:51:14 -08:00
Patrick McCarty 0cc9c4bbf1 Fix up remaining clang-format style issues
Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2020-01-21 15:52:13 -08:00
Tan, Yew Wayne da1a6d63ee Enforce clang-format code style 2020-01-21 15:51:12 -08:00
Tan, Yew Wayne 6144b981d4 Replace all tab indents with space indents 2020-01-21 15:51:12 -08:00
Tan, Yew Wayne 5babb4f44f Free configured urls on server exit 2020-01-21 15:51:12 -08:00
Tan, Yew Wayne aa87b16a54 Document CLR_DEBUGINFO_URLS in drop-in config 2020-01-21 15:51:12 -08:00
Tan, Yew Wayne 91c27b1d2e Configure URLs at runtime from environment variable 2020-01-21 15:51:12 -08:00
Josue David Hernandez Gutierrez e6cbc69e1b Add metadata to follow the same tab setup on emacs or vim
Signed-off-by: Josue David Hernandez Gutierrez <josue.d.hernandez.gutierrez@intel.com>
2019-12-09 15:16:27 -08:00
Auke Kok b1c8be24a2 Add github actions. 2019-11-14 10:27:35 -08:00
Patrick McCarty 7cd99f98ed Release v51
Switches the debuginfo tarball compression format from xz to zstd.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2019-11-13 14:04:27 -08:00
Josue David Hernandez Gutierrez 0387249d7a change xz for zstd
Fixes #4

Signed-off-by: Josue David Hernandez Gutierrez <josue.d.hernandez.gutierrez@intel.com>
2019-11-13 14:02:55 -08:00
Patrick McCarty bca3bdefda Release v50
- Convert clr_debug_prepare to a bash script, also incorporating a few
  improvements and bug fixes into the rewrite.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2019-06-05 15:34:59 -07:00
Patrick McCarty 179392c601 Convert clr_debug_prepare to a bash script
For easier parallelization, I opted to replace the C program with a bash
script that uses GNU Parallel, find, and GAWK for the core control flow.

For compatibility, running the shell script without arguments has the
same general behavior as the C program. Some bugs have been fixed as
well, so the end result should be an improvement over the original.

Bugs fixed:

- A race condition in the C program with the "unsymlink" operation has
  been addressed: instead of replacing the valid symlinks within
  debuginfo.raw, the symlink targets are added directly to the automatic
  tarballs, and tar's "transform" feature is used to rewrite the filename.

- Running system("tar ... &") to create the tarballs often had the side
  effect of bogging down the system, since the number of active tar
  processes had no upper bound. The shell script rewrite uses GNU
  Parallel, which limits (by default) the number of parallel jobs.

- Directory tarballs were unintentionally re-created whenever content
  within the directories were modified, due to the stat() mtime changing.
  With the new script, directory tarball creation only occurs for those
  directories that do not already exist at the destination.

Once the script begins to create tarballs, performance is largely the
same as the C program. The script has a "precompute" phase where it
determines the list of needed tarball creations up-front, which is
different (and probably a bit slower) than the on-the-fly stat()s used
by the C program, but the runtime cost of this new precompute phase is
negligible compared to the tarball creation phase.

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2019-06-05 15:28:20 -07:00
Patrick McCarty b802948209 Release v49
- List tarball contents prior to extraction to improve robustness
- Plug some memory leaks
- Print errors to stderr instead of stdout

Signed-off-by: Patrick McCarty <patrick.mccarty@intel.com>
2019-05-24 13:04:07 -07:00
Auke Kok 4495b923a9 Redo tar extraction - try and make this safe(r).
Instead of extracting to a tmp folder, just tar `tf` it first. This
keeps extracting to the proper locations trivial, at the cost of
decompression the content twice.
2019-05-10 11:08:06 -07:00
Auke Kok 8f7289f028 Test result of tar extraction before trusting the result.
We extract the tarball to a temporary file, before actually allowing
gdb to use this file. This allows us to make sure that gdb doesn't
see the file if it is corrupt. Only if tar exceeds, we rename() the
temp result into the actual needed file. If tar fails, we throw away
the file.
2019-05-07 16:19:36 -07:00
14 changed files with 658 additions and 285 deletions
+19
View File
@@ -0,0 +1,19 @@
name: C/C++ CI
on: [push]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: install dependencies
run: sudo apt-get install libsystemd-dev libcurl4-openssl-dev libfuse-dev
- name: autogen
run: sh autogen.sh
- name: make
run: make
- name: make distcheck
run: make distcheck
+10 -1
View File
@@ -2,7 +2,9 @@
*.o
clr_debug_fuse
clr_debug_daemon
clr_debug_prepare
test-driver
testing_fuse
testing_daemon
.deps/
.dirstamp
Makefile
@@ -30,3 +32,10 @@ config.guess
config.sub
libtool
ltmain.sh
test-suite.log
testing_fuse.log
testing_fuse.trs
testing_daemon.log
testing_daemon.trs
clr_debug_daemon.socket
debuginfo.conf
+12 -4
View File
@@ -14,7 +14,9 @@ AM_CFLAGS = \
AM_CPPFLAGS = $(AM_CFLAGS) ${curl_CFLAGS} ${fuse_CFLAGS}
bin_PROGRAMS = clr_debug_fuse clr_debug_daemon clr_debug_prepare
bin_PROGRAMS = clr_debug_fuse clr_debug_daemon
dist_bin_SCRIPTS = scripts/clr_debug_prepare
noinst_LTLIBRARIES = \
libnica.la
@@ -36,13 +38,19 @@ clr_debug_daemon_CFLAGS = \
$(AM_CFLAGS) \
$(LIBSYSTEMD_CFLAGS)
clr_debug_prepare_SOURCES = src/prepare.c
clr_debug_fuse_LDADD = ${fuse_LIBS} libnica.la
clr_debug_daemon_LDADD = ${curl_LIBS} libnica.la ${LIBSYSTEMD_LIBS}
clr_debug_prepare_LDADD = libnica.la
systemdsystemunit_DATA = clr_debug_fuse.service clr_debug_daemon.service clr_debug_daemon.socket
tmpfiles_DATA = debuginfo.conf
# Functional Testing
noinst_PROGRAMS = testing_fuse testing_daemon
testing_fuse_SOURCES = tests/testing_fuse.c
testing_fuse_CFLAGS = $(AM_CFLAGS)
testing_daemon_SOURCES = tests/testing_daemon.c
testing_daemon_CFLAGS = $(AM_CFLAGS)
@@ -2,7 +2,7 @@
Description=Clear Linux OS debuginfo daemon
[Socket]
ListenStream=/run/clr-debug-info
ListenStream=@SOCKET_PATH@
SocketMode=0600
[Install]
+21 -3
View File
@@ -2,21 +2,21 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.66])
AC_INIT(clr-debug-info, 48, arjan@linux.intel.com)
AC_INIT(clr-debug-info, 52, arjan@linux.intel.com)
AM_INIT_AUTOMAKE([foreign -Wall -W subdir-objects])
AM_SILENT_RULES([yes])
AC_PROG_CC
AM_PROG_AR
AC_LANG(C)
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([clr_debug_daemon.socket])
AC_CONFIG_FILES([debuginfo.conf])
PKG_CHECK_MODULES([curl], [libcurl])
PKG_CHECK_MODULES([fuse], [fuse])
PKG_CHECK_MODULES([SYSTEMD], [systemd])
PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd])
LT_INIT
AC_DEFINE([SOCKET_PATH], ["/run/clr-debug-info"], [path to communication socket])
dir=""
AC_ARG_WITH([systemdsystemunitdir], AS_HELP_STRING([--with-systemdsystemunitdir=DIR],
[path to systemd system service dir @<:@default=/usr/lib/systemd/system@:>@]), [dir=${withval}],
@@ -38,6 +38,22 @@ else
AC_MSG_WARN([C11 stdatomic support unavailable. Falling back to slow mutex])
fi
SOCKET_PATH=""
AC_ARG_WITH([socket-path], AS_HELP_STRING([--with-socket-path=SOCKET_PATH],
[path to create unix socket @<:@default=/run/clr-debug-info@:>@]), [SOCKET_PATH=${withval}],
[SOCKET_PATH="/run/clr-debug-info"])
test -z "${SOCKET_PATH}" && SOCKET_PATH=/run/clr-debug-info
AC_DEFINE_UNQUOTED([SOCKET_PATH], ["${SOCKET_PATH}"], [path to create unix socket @<:@default=/run/clr-debug-info@:>@])
AC_SUBST(SOCKET_PATH, [${SOCKET_PATH}])
CACHE_DIR=""
AC_ARG_WITH([cache-dir], AS_HELP_STRING([--with-cache-dir=CACHE_DIR],
[path to cache downloaded content @<:@default=/var/cache/debuginfo@:>@]), [CACHE_DIR="${withval}"],
[CACHE_DIR="/var/cache/debuginfo"])
test -z "${CACHE_DIR}" && CACHE_DIR=/var/cache/debuginfo
AC_DEFINE_UNQUOTED([CACHE_DIR], ["${CACHE_DIR}"], [path to cache downloaded content @<:@default=/var/cache/debuginfo@:>@])
AC_SUBST(CACHE_DIR, [${CACHE_DIR}])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
@@ -57,6 +73,8 @@ AC_MSG_RESULT([
systemd-unit-dir: ${systemdsystemunitdir}
tmpfiles.d: ${tmpfilesdir}
socket_dir: ${SOCKET_PATH}
cache_dir: ${CACHE_DIR}
C11 stdatomic support: ${have_atomics}
])
+2 -2
View File
@@ -10,5 +10,5 @@
# Clear tmp directories separately, to make them easier to override
# Unfortunatly tmpfiles doesn't change the ownership for things if they
# are not listed.
d /var/cache/debuginfo/lib 755 dbginfo dbginfo 10d
d /var/cache/debuginfo/src 755 dbginfo dbginfo 1d
d @CACHE_DIR@/lib 755 dbginfo dbginfo 10d
d @CACHE_DIR@/src 755 dbginfo dbginfo 1d
+3
View File
@@ -0,0 +1,3 @@
[Service]
# Uncomment to use custom URLs, space separated
#Environment="CLR_DEBUGINFO_URLS=https://cdn-alt.download.clearlinux.org/debuginfo/ https://cdn.download.clearlinux.org/debuginfo/"
+146
View File
@@ -0,0 +1,146 @@
#!/bin/bash
#
# Clear Linux -- automatic debuginfo preparation
#
# Copyright 2019 Intel Corporation
#
# This program is free software: you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation, version 3 or later of the License.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program. If not, see <http://www.gnu.org/licenses/>.
if [ $# -eq 1 ] || [ $# -gt 2 ]; then
echo "Usage: $0 [SOURCEDIR] [DESTDIR]"
echo "Generates automatic debuginfo tarballs in DESTDIR using content from SOURCEDIR."
echo "The default SOURCEDIR and DESTDIR are /var/www/html/debuginfo.raw and"
echo "/var/www/html/debuginfo, respectively."
exit 0
fi >&2
if [ $# -eq 2 ]; then
if [ ! -d "$1" ]; then
echo "ERROR: SOURCEDIR argument must be an existing directory"
exit 1
fi
fi >&2
export SRC="${1:-/var/www/html/debuginfo.raw}"
export DEST="${2:-/var/www/html/debuginfo}"
srclist=$(mktemp -p .)
destlist=$(mktemp -p .)
trap "rm $srclist $destlist" EXIT
set -o pipefail
# First, scan the state of the SRC tree, containing all content for debuginfo RPMs.
if ! find "$SRC" -mindepth 4 -printf "%p %T@ %y\n" | sed "s|$SRC||" | sort -k 1 > "$srclist"; then
echo "ERROR: expected content in $SRC"
exit 1
fi
# Next, scan the state of the DEST tree, containing previously generated
# automatic debuginfo tarballs. Will be empty on first run.
mkdir -p "$DEST"
find "$DEST" -mindepth 2 -name '*.tar' -printf "%p %T@ %y\n" | sed "s|$DEST||;s|\.tar | |" | sort -k 1 > "$destlist"
process_one() {
srcname="$1"
destname="$2"
filetype="$3"
srcloc="$SRC/$srcname"
srcdir="$SRC/$(echo "$srcname" | sed -r 's@^(/usr/(lib|share|src)/debug(/src)?).*@\1@')"
tarcontent="$(echo "$srcname" | sed -r 's@^/usr/(lib|share|src)/debug(/src)?@.@')"
destdir="$DEST/$(dirname "$destname")"
dest="$DEST/$destname.tar"
echo "Creating $destname.tar ..."
mkdir -p "$destdir"
if [ "$filetype" = "f" ]; then
tar --no-recursion -C "$srcdir" --zstd -cf "$dest" "$tarcontent"
elif [ "$filetype" = "l" ]; then
# We "unsymlink" non-broken symlinks as an optimization by adding the
# symlink target to the dest tarball, transforming the name as appropriate.
if target=$(realpath -e "$srcloc" --relative-to="$srcdir" 2> /dev/null); then
tar --no-recursion -C "$srcdir" --zstd -cf "$dest" --transform='s|.*|'"$tarcontent"'|' "$target"
else
tar --no-recursion -C "$srcdir" --zstd -cf "$dest" "$tarcontent"
fi
elif [ "$filetype" = "d" ]; then
tar --no-recursion -C "$srcdir" --zstd -cf "$dest" "$tarcontent"
fi
}
export -f process_one
gawk '
BEGIN { OFS = "\t" }
LIST == "src" {
name = $1
srcname = name
ret = sub(/^\/usr\/lib\/debug/, "/lib", name)
if (ret == 0) {
ret = sub(/^\/usr\/src\/debug/, "/src", name)
if (ret == 0) {
ret = sub(/^\/usr\/share\/debug\/src/, "/src", name)
if (ret == 0) {
ret = sub(/^\/usr\/share\/debug/, "/lib", name)
if (ret == 0) {
print "Error: unexpected debuginfo file:", name
exit 1
}
}
}
}
src[name]["srcname"] = srcname
src[name]["time"] = $2
src[name]["type"] = $3
src[name]["done"] = 0
}
LIST == "dest" {
dest_content = 1
name = $1
time = $2
type = $3
if (name in src) {
# No need to recreate directory tars if they exist
if (src[name]["type"] == "d") {
src[name]["done"] = 1
next
} else {
# Only regenerate content if timestamp is newer
if (time < src[name]["time"]) {
print src[name]["srcname"], name, src[name]["type"]
}
src[name]["done"] = 1
}
}
}
END {
PROCINFO["sorted_in"] = "@ind_str_asc"
if (dest_content == 0) {
for (s in src) {
print src[s]["srcname"], s, src[s]["type"]
}
} else {
for (s in src) {
if (src[s]["done"] == 0) {
print src[s]["srcname"], s, src[s]["type"]
}
}
}
}
' LIST="src" "$srclist" LIST="dest" "$destlist" \
| parallel --colsep '\t' process_one
# vi: ft=sh et sw=2 sts=2
+13
View File
@@ -121,3 +121,16 @@ void try_to_get(const char *path, int pid, time_t timestamp)
close(sockfd);
}
/*
* 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:
*/
+16 -3
View File
@@ -636,8 +636,8 @@ int main(__nc_unused__ int argc, __nc_unused__ char *argv[])
{
char *fake_argv[20];
char *dir = "/usr/src/debug";
char *shadowdir = "/var/cache/debuginfo/src";
const char *required_paths[] = { "/var/cache/debuginfo/lib", "/var/cache/debuginfo/src" };
char *shadowdir = CACHE_DIR "/src";
const char *required_paths[] = { CACHE_DIR "/lib", CACHE_DIR "/src" };
umask(0);
@@ -663,7 +663,7 @@ int main(__nc_unused__ int argc, __nc_unused__ char *argv[])
if (fork() == 0) {
dir = "/usr/lib/debug";
shadowdir = "/var/cache/debuginfo/lib";
shadowdir = CACHE_DIR "/lib";
prefix = "lib";
}
@@ -681,3 +681,16 @@ int main(__nc_unused__ int argc, __nc_unused__ char *argv[])
return fuse_main(9, fake_argv, &xmp_oper, NULL);
}
/*
* 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:
*/
-243
View File
@@ -1,243 +0,0 @@
/*
* Fenrus Linux -- automatic debug information installation
* Clear Linux -- automatic debug information installation
* Server side preparation logic
*
* Copyright (C) 2013 Arjan van de Ven
* Copyright (C) 2014 Intel Corporation
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 or later of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Arjan van de Ven <arjanvandeven@gmail.com>
* Ikey Doherty <michael.i.doherty@intel.com>
*
*/
#define _GNU_SOURCE
#include <dirent.h>
#include <errno.h>
#include <libgen.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include "nica/files.h"
/*
this program takes a directory /var/www/html/debuginfo.raw,
in which all debuginfo rpms have previously been rpm2cpio'd, and
creates the content for /var/www/html/debuginfo
which contains tar'd up/compressed versions of all the files.
As part of this symlinks will be resolved server side
as much as possible.
*/
static void unsymlink(char *filename)
{
char *target;
__nc_unused__ int r;
target = canonicalize_file_name(filename);
// sleep(1);
// printf("Symlink %s points to %s\n", filename, target);
unlink(filename);
r = link(target, filename);
}
static void wait_for_loadavg(void)
{
FILE *file;
char line[4096];
__nc_unused__ char *ret = NULL;
while (1) {
double d;
file = fopen("/proc/loadavg", "r");
if (!file) {
return;
}
line[0] = 0;
ret = fgets(line, 4096, file);
fclose(file);
d = strtod(line, NULL);
if (d < 50) {
return;
}
sleep(5);
}
}
int tarcount;
static void do_one_file(char *base1, char *base2, char *path, int isdir)
{
char *dir2 = NULL;
autofree(char) * fullpath1, *fullpath2, *dir = NULL;
struct stat buf1, buf2;
int ret;
int sret;
if (asprintf(&fullpath1, "%s%s", base1, path) < 0) {
return;
}
if (asprintf(&fullpath2, "%s%s.tar", base2, path) < 0) {
return;
}
ret = lstat(fullpath1, &buf1);
if (ret) {
return;
}
if (S_ISLNK(buf1.st_mode)) {
// printf("%s is a symlink\n", fullpath1);
ret = stat(fullpath1, &buf2);
if (!ret) {
unsymlink(fullpath1);
}
ret = lstat(fullpath1, &buf1);
}
ret = lstat(fullpath2, &buf2);
if (ret || buf1.st_mtime > buf2.st_mtime) {
char *command = NULL;
unlink(fullpath2);
dir = strdup(fullpath2);
dir2 = dirname(dir);
if (dir2) {
(void)nc_mkdir_p(dir2, 00755);
}
if (chdir(base1) != 0) {
fprintf(stderr, "Failed to chdir: %s\n", strerror(errno));
return;
}
if (!isdir &&
asprintf(&command,
"tar --no-recursion -C %s -Jcf %s %s &",
base1,
fullpath2,
path) >= 0) {
// printf("Running -%s-\n", command);
printf("Processing %s\n", fullpath2);
tarcount++;
if (tarcount > 50) {
wait_for_loadavg();
tarcount = 0;
}
if ((sret = system(command)) != 0) {
fprintf(stderr, "Failure in command: [%d] %s\n", sret, command);
}
free(command);
}
if (isdir &&
asprintf(&command,
"tar --no-recursion -C %s -Jcf %s `find %s -type d` `find %s "
"-maxdepth 1 -type l` &",
base1,
fullpath2,
path,
path) >= 0) {
// printf("Running -%s-\n", command);
printf("Processing %s\n", fullpath2);
tarcount++;
if (tarcount > 50) {
wait_for_loadavg();
tarcount = 0;
}
if ((sret = system(command)) != 0) {
fprintf(stderr, "Failure in command: [%d] %s\n", sret, command);
}
free(command);
}
}
}
static void recurse_dir(char *base1, char *base2, char *path)
{
DIR *dir;
char *fullpath1 = NULL;
struct dirent *entry;
if (asprintf(&fullpath1, "%s%s", base1, path) < 0) {
return;
}
dir = opendir(fullpath1);
if (!dir) {
return;
}
while (1) {
autofree(char) *fullpath2 = NULL;
autofree(char) *newpath = NULL;
entry = readdir(dir);
if (!entry) {
break;
}
if (strcmp(entry->d_name, ".") == 0) {
continue;
}
if (strcmp(entry->d_name, "..") == 0) {
continue;
}
newpath = NULL;
fullpath2 = NULL;
if (asprintf(&fullpath2, "%s/%s", fullpath1, entry->d_name) < 0) {
return;
}
if (asprintf(&newpath, "%s/%s", path, entry->d_name) >= 0) {
struct stat sb;
stat(fullpath2, &sb);
if (entry->d_type == DT_DIR || S_ISDIR(sb.st_mode)) {
do_one_file(base1, base2, newpath, 1);
recurse_dir(base1, base2, newpath);
} else {
do_one_file(base1, base2, newpath, 0);
}
}
}
closedir(dir);
}
int main(int argc, char **argv)
{
if (argc < 0)
(void)argv;
recurse_dir("/var/www/html/debuginfo.raw/usr/lib/debug/",
"/var/www/html/debuginfo/lib/",
".");
recurse_dir("/var/www/html/debuginfo.raw/usr/src/debug/",
"/var/www/html/debuginfo/src/",
".");
return EXIT_SUCCESS;
}
+140 -28
View File
@@ -2,7 +2,7 @@
* Clear Linux -- automatic debug information installation
*
* Copyright (C) 2013 Arjan van de Ven
* Curl portions borrowed from the Fenrus Update code
* Curl portions borrowed from the Fenrus Update code
* which in part is (C) 2012 Intel Corporation
* Copyright (C) 2014 Intel Corporation
*
@@ -28,6 +28,7 @@
#include <errno.h>
#include <grp.h>
#include <libgen.h>
#include <linux/capability.h>
#include <malloc.h>
#include <pthread.h>
@@ -61,9 +62,11 @@
static pthread_mutex_t dupes_mutex = PTHREAD_MUTEX_INITIALIZER;
char *urls[2] = { "https://cdn.download.clearlinux.org/debuginfo/",
"https://cdn-alt.download.clearlinux.org/debuginfo/" };
char *urls_default[] = { "https://cdn.download.clearlinux.org/debuginfo/",
"https://cdn-alt.download.clearlinux.org/debuginfo/" };
int urls_size = 2;
int urlcounter = 1;
char **urls = urls_default;
static NcHashmap *hash = NULL;
@@ -96,6 +99,60 @@ static int avoid_dupes(const char *url)
return retval;
}
/*
* Read URLs from environment variable, space separated
*/
int configure_urls(void)
{
const char *env_var = getenv("CLR_DEBUGINFO_URLS");
const char *token = env_var;
int count = 0;
char **urls_new = NULL;
if (env_var) {
while (1) {
int token_len = strcspn(token, " \t\n");
if (token_len) {
count++;
urls_new = realloc(urls_new, count * sizeof(char *));
if (!urls_new) {
perror("realloc()");
exit(EXIT_FAILURE);
}
char *url = calloc(token_len + 1, sizeof(char));
if (!url) {
perror("calloc()");
exit(EXIT_FAILURE);
}
urls_new[count - 1] = strncpy(url, token, token_len);
token += token_len;
}
if (*token == '\0') {
break;
}
token++;
}
}
if (count) {
// Abandon defaults
urls = urls_new;
urls_size = count;
urlcounter = 0;
}
return count;
}
void free_urls(void)
{
if (urls != urls_default) {
for (int i = 0; i < urls_size; i++) {
free(urls[i]);
}
free(urls);
}
}
#ifdef HAVE_ATOMIC_SUPPORT
static atomic_int current_connection_count = 0;
@@ -170,10 +227,9 @@ static int curl_get_file(const char *url, const char *prefix, time_t timestamp)
long ret;
long changed;
int fd;
char filename[PATH_MAX];
autofree(char) *filename = NULL;
CURL *curl = NULL;
FILE *file;
struct stat statbuf;
if (avoid_dupes(url)) {
return 300;
@@ -184,12 +240,15 @@ static int curl_get_file(const char *url, const char *prefix, time_t timestamp)
return 301;
}
strcpy(filename, "/tmp/clr-debug-info-XXXXXX");
// fprintf(stderr, "Fetching %s, prefix %s, path %s\n", url, prefix, path);
if (asprintf(&filename, "/tmp/clr-debug-info-XXXXXX") < 0) {
curl_easy_cleanup(curl);
return 418;
}
fd = mkstemp(filename);
if (fd < 0) {
curl_easy_cleanup(curl);
return 500;
return 418;
}
file = fdopen(fd, "w");
@@ -227,7 +286,7 @@ static int curl_get_file(const char *url, const char *prefix, time_t timestamp)
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &ret);
fflush(file);
// printf("HTTP return code is %i\n", ret);
// printf("HTTP return code is %i\n", ret);
/* HTTP 304 is returned if (a) the cached debuginfo has the same
* timestamp or is newer than that on the server and (b) we haven't
@@ -240,6 +299,9 @@ static int curl_get_file(const char *url, const char *prefix, time_t timestamp)
}
if (ret == 200) {
autofree(char) *command = NULL;
struct stat statbuf;
/* get timestamp, if any */
curl_easy_getinfo(curl, CURLINFO_FILETIME, &changed);
if (changed >= 0) {
@@ -251,22 +313,49 @@ static int curl_get_file(const char *url, const char *prefix, time_t timestamp)
futimens(fd, times);
}
autofree(char) *command = NULL;
// printf("Filename is %s\n", filename);
memset(&statbuf, 0, sizeof(statbuf));
stat(filename, &statbuf);
if (statbuf.st_size > 0 &&
asprintf(&command,
"tar -C /var/cache/debuginfo/%s --no-same-owner "
"--no-same-permissions -xf %s",
if (statbuf.st_size <= 0) {
ret = 418;
goto out;
}
/* test extraction first */
if (asprintf(&command,
"tar -C %s/%s --no-same-owner "
"--no-same-permissions -tf %s",
CACHE_DIR,
prefix,
filename) >= 0) {
if (system(command) != 0) {
fputs("Warning: tar extraction failed\n", stderr);
}
filename) < 0) {
ret = 418;
goto out;
}
if (system(command) != 0) {
ret = 418;
fprintf(stderr, "Error: tar validation failed\n");
goto out;
}
free(command); /* reuse */
if (asprintf(&command,
"tar -C %s/%s --no-same-owner "
"--no-same-permissions -xf %s",
CACHE_DIR,
prefix,
filename) < 0) {
ret = 418;
goto out;
}
if (system(command) != 0) {
ret = 418;
fprintf(stderr, "Error: tar extraction failed\n");
goto out;
}
}
out:
unlink(filename);
curl_easy_cleanup(curl);
fclose(file);
@@ -336,11 +425,11 @@ static void *server_thread(void *arg)
goto thread_end;
}
url = NULL;
if (asprintf(&url, "%s%s%s.tar", urls[urlcounter % 2], prefix, path) < 0) {
if (asprintf(&url, "%s%s%s.tar", urls[urlcounter % urls_size], prefix, path) < 0) {
goto thread_end;
}
// printf("Getting url %s %i:%06i\n", url, before.tv_sec, before.tv_usec);
// printf("Getting url %s %i:%06i\n", url, before.tv_sec, before.tv_usec);
ret = curl_get_file(url, prefix, timestamp);
switch (ret) {
@@ -351,7 +440,7 @@ static void *server_thread(void *arg)
// ignore these error codes
break;
default:
printf("Request for %s resulted in error %i\n", url, ret);
fprintf(stderr, "Request for %s resulted in error %i\n", url, ret);
break;
}
@@ -385,7 +474,16 @@ int main(__nc_unused__ int argc, __nc_unused__ char **argv)
uid_t dbg_user = 0;
gid_t dbg_group = 0;
struct passwd *passwdentry;
const char *required_paths[] = { "/var/cache/debuginfo/lib", "/var/cache/debuginfo/src" };
const char *required_paths[] = { CACHE_DIR "/lib", CACHE_DIR "/src" };
if (configure_urls()) {
fprintf(stderr, "Using urls from environment\n");
} else {
fprintf(stderr, "Using compiled default urls\n");
}
for (int i = 0; i < urls_size; i++) {
fprintf(stderr, "url: %s\n", urls[i]);
}
umask(0);
passwdentry = getpwnam("dbginfo");
@@ -437,7 +535,7 @@ int main(__nc_unused__ int argc, __nc_unused__ char **argv)
/* systemd socket activation */
sockfd = SD_LISTEN_FDS_START + 0;
} else if (sd_listen_fds(0) > 1) {
printf("Too many file descriptors received.\n");
fprintf(stderr, "Too many file descriptors received.\n");
exit(EXIT_FAILURE);
} else {
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
@@ -449,8 +547,8 @@ int main(__nc_unused__ int argc, __nc_unused__ char **argv)
strcpy(sun.sun_path, SOCKET_PATH);
ret = bind(sockfd,
(struct sockaddr *)&sun,
offsetof(struct sockaddr_un, sun_path) + strlen(SOCKET_PATH) + 1);
(struct sockaddr *)&sun,
offsetof(struct sockaddr_un, sun_path) + strlen(SOCKET_PATH) + 1);
if (ret < 0) {
fprintf(stderr, "Failed to bind:%s \n", strerror(errno));
exit(EXIT_FAILURE);
@@ -497,7 +595,6 @@ int main(__nc_unused__ int argc, __nc_unused__ char **argv)
break;
}
clientsock = accept(sockfd, NULL, NULL);
/* Too many connections, wait for the next loop/retry */
@@ -522,4 +619,19 @@ int main(__nc_unused__ int argc, __nc_unused__ char **argv)
if (hash) {
nc_hashmap_free(hash);
}
free_urls();
}
/*
* 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:
*/
+104
View File
@@ -0,0 +1,104 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <string.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <signal.h>
#include <unistd.h>
#include <errno.h>
#include "config.h"
#define BUFFER_LENGTH 16
int get_server_socket(void)
{
int sockfd;
struct sockaddr_un serveraddr;
fputs("Creating socket\n", stderr);
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) {
fputs("Fail creating socket\n", stderr);
return -1;
}
memset(&serveraddr, 0, sizeof(serveraddr));
serveraddr.sun_family = AF_UNIX;
strcpy(serveraddr.sun_path, SOCKET_PATH);
fputs("Connecting to server\n", stderr);
if (connect(sockfd, (struct sockaddr*)&serveraddr,
offsetof(struct sockaddr_un, sun_path) + strlen(SOCKET_PATH) + 1) < 0) {
fprintf(stderr, "Fail connecting to server: %s\n", strerror(errno));
close(sockfd);
return -1;
}
return sockfd;
}
int testing_daemon(void)
{
int sockfd;
char buffer[BUFFER_LENGTH];
if((sockfd = get_server_socket()) < 0) {
return -1;
}
fputs("Sending message to server\n", stderr);
memset(buffer, 0, sizeof(buffer));
strcpy(buffer, "0:lib:/lib");
if(send(sockfd, buffer, sizeof(buffer), 0) < 0) {
fputs("Fail sending message to socket service\n", stderr);
close(sockfd);
return -1;
}
fputs("Receiving message from server\n", stderr);
memset(buffer, 0, sizeof(buffer));
if (recv(sockfd, &buffer[0],
BUFFER_LENGTH, 0) < 0) {
fputs("Failing receiving message from socket service\n", stderr);
close(sockfd);
return -1;
}
close(sockfd);
return strcmp(buffer, "ok") && access(CACHE_DIR "/lib/lib", F_OK) != -1;
}
int main(void)
{
int res = 0;
pid_t p;
p = fork();
if (p == 0) {
if (freopen("/dev/null", "w", stderr) == NULL)
return -1;
char *args[] = {"./clr_debug_daemon", NULL};
execvp("./clr_debug_daemon", args);
} else if (p > 0) {
sleep(1);
res = testing_daemon();
kill(p, SIGKILL);
} else {
fputs("error executing fork\n", stderr);
}
unlink(SOCKET_PATH);
return res;
}
/*
* 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:
*/
+171
View File
@@ -0,0 +1,171 @@
#define _GNU_SOURCE
#include <errno.h>
#include <grp.h>
#include <linux/capability.h>
#include <linux/limits.h>
#include <malloc.h>
#include <pwd.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include "config.h"
#define TIMEOUT 600
#define MAX_CONNECTIONS 16
int check_file_request(int fd, char *expected_str)
{
char buf[PATH_MAX + 8];
int clientsock;
malloc_trim(0);
fputs("Accepting connection\n", stderr);
clientsock = accept(fd, NULL, NULL);
if (clientsock < 0)
return -1;
memset(buf, 0, sizeof(buf));
fputs("Reading socket content\n", stderr);
if (read(clientsock, buf, PATH_MAX + 8) < 0)
return -1;
close(clientsock);
return strncmp(buf, expected_str, strlen(expected_str));
}
int get_service_socket(void)
{
int sockfd;
struct sockaddr_un sun;
signal(SIGPIPE, SIG_IGN);
fputs("Creating socket\n", stderr);
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) {
fputs("Fail creating socket\n", stderr);
return -1;
}
printf("Socket path %s\n", SOCKET_PATH);
sun.sun_family = AF_UNIX;
strcpy(sun.sun_path, SOCKET_PATH);
fputs("Binding socket\n", stderr);
if (bind(sockfd, (struct sockaddr*)&sun,
offsetof(struct sockaddr_un, sun_path) + strlen(SOCKET_PATH) + 1) < 0) {
fprintf(stderr, "fail bind: %s\n", strerror(errno));
close(sockfd);
return -1;
}
if (listen(sockfd, 16) < 0) {
fputs("Fail listening socket \n", stderr);
close(sockfd);
return -1;
}
return sockfd;
}
int testing_fuse(void)
{
int sockfd;
uid_t gdb_user = 0;
gid_t gdb_group = 0;
struct passwd *passwdentry;
pid_t p2;
int test_result = -1;
umask(0);
passwdentry = getpwnam("gdbinfo");
if (passwdentry) {
gdb_user = passwdentry->pw_uid;
gdb_group = passwdentry->pw_gid;
}
endpwent();
if (prctl(PR_SET_DUMPABLE, 0) != 0) {
fputs("fail prctl\n", stderr);
}
if (geteuid() == 0) {
if (prctl(PR_CAPBSET_DROP, CAP_SYS_ADMIN) !=0) {
fprintf(stderr, "fail geteuid: %s\n", strerror(errno));
}
}
if ((sockfd = get_service_socket()) < 0) {
return 1;
}
if (setgid(gdb_group)) {
fputs("fail setgid\n", stderr);
}
if (setgroups(1, &gdb_group)) {
fputs("fail setgroups\n", stderr);
}
if (setuid(gdb_user)) {
fputs("fail setuid\n", stderr);
}
p2 = fork();
if (p2 > 0) {
test_result = check_file_request(sockfd, "0:lib:/tmp");
} else if (p2 == 0) {
if (freopen("/dev/null", "w", stderr) == NULL)
exit(1);
char *args[] = {"/usr/bin/cat", "/usr/lib/debug/tmp", NULL};
execvp("/usr/bin/cat", args);
} else {
fputs("error executing fork\n", stderr);
return 1;
}
wait(NULL);
close(sockfd);
return test_result;
}
int main(void)
{
int res = 0;
pid_t p;
p = fork();
if (p == 0) {
if (freopen("/dev/null", "w", stderr) == NULL)
return -1;
char *args[] = {"./clr_debug_fuse", NULL};
execvp("./clr_debug_fuse", args);
} else if (p > 0) {
sleep(1);
res = testing_fuse();
kill(p, SIGKILL);
} else {
fputs("error executing fork\n", stderr);
return 1;
}
unlink(SOCKET_PATH);
return res;
}
/*
* 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:
*/