mirror of
https://github.com/clearlinux/clr-debug-info.git
synced 2026-09-06 05:41:43 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
251b7cfe3b | ||
|
|
97d255f115 | ||
|
|
1a36c33e6e | ||
|
|
b8568a3959 | ||
|
|
0cc9c4bbf1 | ||
|
|
da1a6d63ee | ||
|
|
6144b981d4 | ||
|
|
5babb4f44f | ||
|
|
aa87b16a54 | ||
|
|
91c27b1d2e | ||
|
|
e6cbc69e1b | ||
|
|
b1c8be24a2 | ||
|
|
7cd99f98ed | ||
|
|
0387249d7a | ||
|
|
bca3bdefda | ||
|
|
179392c601 | ||
|
|
b802948209 | ||
|
|
4495b923a9 | ||
|
|
8f7289f028 | ||
|
|
dc376d5e8b | ||
|
|
c831ecb902 | ||
|
|
0978d429b2 | ||
|
|
6653992aba | ||
|
|
0af0308dd2 | ||
|
|
8ace503438 | ||
|
|
2c87f83adc | ||
|
|
67b9b3acc8 | ||
|
|
d108c0af64 | ||
|
|
98e802b4cc | ||
|
|
612801b0c8 | ||
|
|
3c2ad26baa | ||
|
|
d20d585e5c | ||
|
|
1f3a0f0be4 | ||
|
|
d2d67bdb1d | ||
|
|
60db7bab0f | ||
|
|
ef6b11498a | ||
|
|
efeed3e83f | ||
|
|
f5542e7fbb | ||
|
|
be8a99da53 | ||
|
|
c9304402e2 | ||
|
|
6e202f13f7 | ||
|
|
6735f8f6ed | ||
|
|
8b3777ab99 | ||
|
|
84350939ef | ||
|
|
72b1120a40 | ||
|
|
d3d5fab301 | ||
|
|
e377433a9d | ||
|
|
afa92c77b1 | ||
|
|
a01ce4c329 | ||
|
|
1eaaac582c | ||
|
|
935dbee3c7 | ||
|
|
0065ef2670 | ||
|
|
b5b4030f7c | ||
|
|
de9e0ce5c5 | ||
|
|
9e400bd149 | ||
|
|
f5a65358af | ||
|
|
c82a007960 | ||
|
|
02ece110b5 | ||
|
|
3a6bf4a167 | ||
|
|
fc61591870 | ||
|
|
2f26fc55c7 | ||
|
|
dfff530803 | ||
|
|
9685fcb632 | ||
|
|
14495e064b | ||
|
|
7b64fb601d | ||
|
|
b24d93fe3d | ||
|
|
5b7c484b64 | ||
|
|
d23b8e17bd | ||
|
|
b120d1c38f | ||
|
|
bbc34ad790 | ||
|
|
caf84d9b5f | ||
|
|
bc276b4920 | ||
|
|
78485dc583 | ||
|
|
ce02c64c0c | ||
|
|
f272c08d4f | ||
|
|
3babbe4b7b | ||
|
|
aad87bbdc1 | ||
|
|
4505d32c68 | ||
|
|
67a9735acb | ||
|
|
1c043d5bd7 | ||
|
|
8c01f4012f | ||
|
|
955c1b7e99 | ||
|
|
a92e6f386a |
@@ -0,0 +1,84 @@
|
|||||||
|
---
|
||||||
|
AccessModifierOffset: 0
|
||||||
|
AlignAfterOpenBracket: true
|
||||||
|
AlignConsecutiveAssignments: false
|
||||||
|
#uncomment for clang 3.9
|
||||||
|
#AlignConsecutiveDeclarations: false
|
||||||
|
AlignEscapedNewlinesLeft: false
|
||||||
|
AlignOperands: true
|
||||||
|
AlignTrailingComments: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: false
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
AllowShortIfStatementsOnASingleLine: false
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
# AlwaysBreakAfterDefinitionReturnType: None
|
||||||
|
#uncomment for clang 3.9
|
||||||
|
#AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: true
|
||||||
|
AlwaysBreakTemplateDeclarations: false
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: true
|
||||||
|
# BraceWrapping: (not set since BreakBeforeBraces is not Custom)
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
# BreakAfterJavaFieldAnnotations: (not java)
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Linux
|
||||||
|
BreakBeforeTernaryOperators: true
|
||||||
|
BreakConstructorInitializersBeforeComma: false
|
||||||
|
#uncomment for clang 3.9
|
||||||
|
#BreakStringLiterals: false
|
||||||
|
ColumnLimit: 100
|
||||||
|
CommentPragmas: '\*\<'
|
||||||
|
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
Cpp11BracedListStyle: false
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
DisableFormat: false
|
||||||
|
ExperimentalAutoDetectBinPacking: false
|
||||||
|
ForEachMacros: [ NC_LIST_FOREACH ]
|
||||||
|
#Uncomment for clang 3.9
|
||||||
|
#IncludeCategories:
|
||||||
|
# - Regex: '^"'
|
||||||
|
# Priority: 1
|
||||||
|
# IncludeIsMainRegex: (project doesn't use a main includes that can add other includes via regex)
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentWidth: 8
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
# JavaScriptQuotes: (not javascript)
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
Language: Cpp
|
||||||
|
MacroBlockBegin: ''
|
||||||
|
MacroBlockEnd: ''
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
NamespaceIndentation: None
|
||||||
|
# ObjCBlockIndentWidth: (not objc)
|
||||||
|
# ObjCSpaceAfterProperty: (not objc)
|
||||||
|
# ObjCSpaceBeforeProtocolList: (not objc)
|
||||||
|
PenaltyBreakBeforeFirstCallParameter: 400
|
||||||
|
PenaltyBreakComment: 0
|
||||||
|
# PenaltyBreakFirstLessLess: (not cpp)
|
||||||
|
PenaltyBreakString: 500
|
||||||
|
PenaltyExcessCharacter: 10000
|
||||||
|
PenaltyReturnTypeOnItsOwnLine: 600
|
||||||
|
PointerAlignment: Right
|
||||||
|
#uncomment for clang 3.9
|
||||||
|
#ReflowComments: true
|
||||||
|
#uncomment for clang 3.9
|
||||||
|
#SortIncludes: true
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesBeforeTrailingComments: 1
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
# SpacesInContainerLiterals: (not objc or javascript)
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: Cpp11
|
||||||
|
TabWidth: 8
|
||||||
|
UseTab: Never
|
||||||
|
...
|
||||||
@@ -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
|
||||||
+18
-1
@@ -2,12 +2,15 @@
|
|||||||
*.o
|
*.o
|
||||||
clr_debug_fuse
|
clr_debug_fuse
|
||||||
clr_debug_daemon
|
clr_debug_daemon
|
||||||
clr_debug_prepare
|
test-driver
|
||||||
|
testing_fuse
|
||||||
|
testing_daemon
|
||||||
.deps/
|
.deps/
|
||||||
.dirstamp
|
.dirstamp
|
||||||
Makefile
|
Makefile
|
||||||
Makefile.in
|
Makefile.in
|
||||||
aclocal.m4
|
aclocal.m4
|
||||||
|
ar-lib
|
||||||
autom4te.cache/
|
autom4te.cache/
|
||||||
compile
|
compile
|
||||||
config.h
|
config.h
|
||||||
@@ -22,3 +25,17 @@ stamp-h1
|
|||||||
*.tar.gz
|
*.tar.gz
|
||||||
tags
|
tags
|
||||||
cscope.*
|
cscope.*
|
||||||
|
*.la
|
||||||
|
*.lo
|
||||||
|
.libs/
|
||||||
|
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
|
||||||
+42
-9
@@ -1,23 +1,56 @@
|
|||||||
EXTRA_DIST = COPYING clr_debug_fuse.service clr_debug_daemon.service debuginfo.conf
|
EXTRA_DIST = COPYING clr_debug_fuse.service clr_debug_daemon.service clr_debug_daemon.socket debuginfo.conf
|
||||||
|
|
||||||
DISTCHECK_CONFIGURE_FLAGS = \
|
DISTCHECK_CONFIGURE_FLAGS = \
|
||||||
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) \
|
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) \
|
||||||
--with-systemdtmpfilesdir=$$dc_install_base/$(tmpfilesdir)
|
--with-systemdtmpfilesdir=$$dc_install_base/$(tmpfilesdir)
|
||||||
|
|
||||||
bin_PROGRAMS = clr_debug_fuse clr_debug_daemon clr_debug_prepare
|
AM_CFLAGS = \
|
||||||
|
-fstack-protector -Wall -pedantic \
|
||||||
|
-Wstrict-prototypes -Wundef -fno-common \
|
||||||
|
-Werror-implicit-function-declaration \
|
||||||
|
-Wformat -Wformat-security -Werror=format-security \
|
||||||
|
-Wno-conversion -Wunused-variable -Wunreachable-code \
|
||||||
|
-Wall -W -D_FORTIFY_SOURCE=2 -std=c11
|
||||||
|
|
||||||
|
AM_CPPFLAGS = $(AM_CFLAGS) ${curl_CFLAGS} ${fuse_CFLAGS}
|
||||||
|
|
||||||
|
bin_PROGRAMS = clr_debug_fuse clr_debug_daemon
|
||||||
|
|
||||||
|
dist_bin_SCRIPTS = scripts/clr_debug_prepare
|
||||||
|
|
||||||
|
noinst_LTLIBRARIES = \
|
||||||
|
libnica.la
|
||||||
|
|
||||||
|
# Extract of libnica components
|
||||||
|
libnica_la_SOURCES = \
|
||||||
|
src/nica/files.c \
|
||||||
|
src/nica/files.h \
|
||||||
|
src/nica/hashmap.c \
|
||||||
|
src/nica/hashmap.h \
|
||||||
|
src/nica/util.h
|
||||||
|
|
||||||
|
|
||||||
clr_debug_fuse_SOURCES = src/fuse.c src/client.c
|
clr_debug_fuse_SOURCES = src/fuse.c src/client.c
|
||||||
|
|
||||||
clr_debug_daemon_SOURCES = src/server.c
|
clr_debug_daemon_SOURCES = src/server.c
|
||||||
|
clr_debug_daemon_CFLAGS = \
|
||||||
clr_debug_prepare_SOURCES = src/prepare.c
|
-pthread \
|
||||||
|
$(AM_CFLAGS) \
|
||||||
|
$(LIBSYSTEMD_CFLAGS)
|
||||||
|
|
||||||
|
|
||||||
AM_CPPFLAGS = $(AM_CFLAGS) $(glib_CFLAGS) ${curl_CFLAGS} ${fuse_CFLAGS}
|
clr_debug_fuse_LDADD = ${fuse_LIBS} libnica.la
|
||||||
clr_debug_fuse_LDADD = ${fuse_LIBS} $(glib_LIBS)
|
clr_debug_daemon_LDADD = ${curl_LIBS} libnica.la ${LIBSYSTEMD_LIBS}
|
||||||
clr_debug_daemon_LDADD = $(glib_LIBS) ${curl_LIBS}
|
|
||||||
clr_debug_prepare_LDADD = $(glib_LIBS)
|
|
||||||
|
|
||||||
systemdsystemunit_DATA = clr_debug_fuse.service clr_debug_daemon.service
|
systemdsystemunit_DATA = clr_debug_fuse.service clr_debug_daemon.service clr_debug_daemon.socket
|
||||||
|
|
||||||
tmpfiles_DATA = debuginfo.conf
|
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)
|
||||||
|
|||||||
Executable
+14
@@ -0,0 +1,14 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
autoreconf --force --install --symlink --warnings=all
|
||||||
|
|
||||||
|
args="\
|
||||||
|
--sysconfdir=/etc \
|
||||||
|
--localstatedir=/var \
|
||||||
|
--prefix=/usr \
|
||||||
|
--enable-silent-rules"
|
||||||
|
|
||||||
|
./configure CFLAGS="-g -O1 $CFLAGS" $args "$@"
|
||||||
|
make clean
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Clear Linux debuginfo daemon
|
Description=Clear Linux debuginfo daemon
|
||||||
|
DefaultDependencies=no
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Clear Linux OS debuginfo daemon
|
||||||
|
|
||||||
|
[Socket]
|
||||||
|
ListenStream=@SOCKET_PATH@
|
||||||
|
SocketMode=0600
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=sockets.target
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
[Unit]
|
[Unit]
|
||||||
Description=Clear Linux debuginfo fuse monitor
|
Description=Clear Linux debuginfo fuse monitor
|
||||||
After=clr_debug_daemon.service
|
After=clr_debug_daemon.socket
|
||||||
|
Requires=clr_debug_daemon.socket
|
||||||
|
DefaultDependencies=no
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
Type=simple
|
Type=simple
|
||||||
|
|||||||
+51
-2
@@ -2,16 +2,20 @@
|
|||||||
# Process this file with autoconf to produce a configure script.
|
# Process this file with autoconf to produce a configure script.
|
||||||
|
|
||||||
AC_PREREQ([2.66])
|
AC_PREREQ([2.66])
|
||||||
AC_INIT(clr-debug-info, 30, arjan@linux.intel.com)
|
AC_INIT(clr-debug-info, 52, arjan@linux.intel.com)
|
||||||
AM_INIT_AUTOMAKE([foreign -Wall -W subdir-objects])
|
AM_INIT_AUTOMAKE([foreign -Wall -W subdir-objects])
|
||||||
AM_SILENT_RULES([yes])
|
AM_SILENT_RULES([yes])
|
||||||
AC_PROG_CC
|
AC_PROG_CC
|
||||||
|
AM_PROG_AR
|
||||||
AC_LANG(C)
|
AC_LANG(C)
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
PKG_CHECK_MODULES([glib], [glib-2.0 gthread-2.0])
|
AC_CONFIG_FILES([clr_debug_daemon.socket])
|
||||||
|
AC_CONFIG_FILES([debuginfo.conf])
|
||||||
PKG_CHECK_MODULES([curl], [libcurl])
|
PKG_CHECK_MODULES([curl], [libcurl])
|
||||||
PKG_CHECK_MODULES([fuse], [fuse])
|
PKG_CHECK_MODULES([fuse], [fuse])
|
||||||
PKG_CHECK_MODULES([SYSTEMD], [systemd])
|
PKG_CHECK_MODULES([SYSTEMD], [systemd])
|
||||||
|
PKG_CHECK_MODULES([LIBSYSTEMD], [libsystemd])
|
||||||
|
LT_INIT
|
||||||
|
|
||||||
dir=""
|
dir=""
|
||||||
AC_ARG_WITH([systemdsystemunitdir], AS_HELP_STRING([--with-systemdsystemunitdir=DIR],
|
AC_ARG_WITH([systemdsystemunitdir], AS_HELP_STRING([--with-systemdsystemunitdir=DIR],
|
||||||
@@ -27,5 +31,50 @@ AC_ARG_WITH([systemdtmpfilesdir], AS_HELP_STRING([--with-systemdtmpfilesdir=DIR]
|
|||||||
test -z "${dir}" && dir=/usr/lib/tmpfiles.d
|
test -z "${dir}" && dir=/usr/lib/tmpfiles.d
|
||||||
AC_SUBST(tmpfilesdir, [${dir}])
|
AC_SUBST(tmpfilesdir, [${dir}])
|
||||||
|
|
||||||
|
AC_CHECK_HEADER([stdatomic.h], [have_atomics="yes"], [have_atomics="no"])
|
||||||
|
if test x$have_atomics = "xyes"; then
|
||||||
|
AC_DEFINE([HAVE_ATOMIC_SUPPORT], [1], [stdatomic supported by compiler])
|
||||||
|
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_CONFIG_FILES([Makefile])
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
|
AC_MSG_RESULT([
|
||||||
|
clr-debuginfo $VERSION
|
||||||
|
|
||||||
|
prefix: ${prefix}
|
||||||
|
libdir: ${libdir}
|
||||||
|
sysconfdir: ${sysconfdir}
|
||||||
|
exec_prefix: ${exec_prefix}
|
||||||
|
bindir: ${bindir}
|
||||||
|
datarootdir: ${datarootdir}
|
||||||
|
|
||||||
|
compiler: ${CC}
|
||||||
|
cflags: ${CFLAGS}
|
||||||
|
ldflags: ${LDFLAGS}
|
||||||
|
|
||||||
|
systemd-unit-dir: ${systemdsystemunitdir}
|
||||||
|
tmpfiles.d: ${tmpfilesdir}
|
||||||
|
socket_dir: ${SOCKET_PATH}
|
||||||
|
cache_dir: ${CACHE_DIR}
|
||||||
|
|
||||||
|
C11 stdatomic support: ${have_atomics}
|
||||||
|
])
|
||||||
|
|||||||
@@ -8,5 +8,7 @@
|
|||||||
# See tmpfiles.d(5) for details
|
# See tmpfiles.d(5) for details
|
||||||
|
|
||||||
# Clear tmp directories separately, to make them easier to override
|
# Clear tmp directories separately, to make them easier to override
|
||||||
d /var/cache/debuginfo/lib 755 root root 10d
|
# Unfortunatly tmpfiles doesn't change the ownership for things if they
|
||||||
d /var/cache/debuginfo/src 755 root root 1d
|
# are not listed.
|
||||||
|
d @CACHE_DIR@/lib 755 dbginfo dbginfo 10d
|
||||||
|
d @CACHE_DIR@/src 755 dbginfo dbginfo 1d
|
||||||
@@ -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/"
|
||||||
Executable
+146
@@ -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
|
||||||
+89
-68
@@ -7,36 +7,40 @@
|
|||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, version 2 or later of the License.
|
* the Free Software Foundation, version 2 or later of the License.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Arjan van de Ven <arjanvandeven@gmail.com>
|
* Arjan van de Ven <arjanvandeven@gmail.com>
|
||||||
|
* Ikey Doherty <michael.i.doherty@intel.com>
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include "nica/util.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stddef.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/un.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
/* 0.75 seconds timeout */
|
/* 0.75 seconds timeout */
|
||||||
#define TIMEOUT 750000
|
#define TIMEOUT 75000
|
||||||
#define TIMEOUT2 15000
|
#define TIMEOUT2 1500
|
||||||
#define TIMEOUT3 500
|
#define TIMEOUT3 500
|
||||||
|
|
||||||
char *prefix = "src";
|
char *prefix = "src";
|
||||||
@@ -45,71 +49,88 @@ time_t deadtime;
|
|||||||
|
|
||||||
void try_to_get(const char *path, int pid, time_t timestamp)
|
void try_to_get(const char *path, int pid, time_t timestamp)
|
||||||
{
|
{
|
||||||
int sockfd;
|
int sockfd;
|
||||||
struct sockaddr_un sun;
|
struct sockaddr_un sun;
|
||||||
int ret;
|
int ret;
|
||||||
socklen_t len;
|
socklen_t len;
|
||||||
char *command;
|
char *command;
|
||||||
fd_set rfds;
|
fd_set rfds;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
struct ucred cred;
|
struct ucred cred;
|
||||||
int shorttime = 0;
|
int shorttime = 0;
|
||||||
|
__nc_unused__ size_t wr = -1;
|
||||||
// printf("Trying to aquire %s\n", path);
|
|
||||||
|
|
||||||
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
|
||||||
if (sockfd < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
sun.sun_family = AF_UNIX;
|
|
||||||
strcpy(sun.sun_path, ":clr-debug-info");
|
|
||||||
sun.sun_path[0] = 0; /* anonymous unix socket */
|
|
||||||
|
|
||||||
ret = connect(sockfd, (struct sockaddr *)&sun, offsetof(struct sockaddr_un, sun_path) + strlen(":clr-debug-info") + 1);
|
// printf("Trying to aquire %s\n", path);
|
||||||
if (ret < 0) {
|
|
||||||
printf("Cannot connect %s\n", strerror(errno));
|
|
||||||
close(sockfd);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = sizeof(cred);
|
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
memset(&cred, 0, sizeof(cred));
|
if (sockfd < 0) {
|
||||||
ret = getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &len);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (ret == 0 && cred.pid == pid) {
|
sun.sun_family = AF_UNIX;
|
||||||
printf("Recursion\n");
|
strcpy(sun.sun_path, SOCKET_PATH);
|
||||||
close(sockfd);
|
|
||||||
}
|
|
||||||
|
|
||||||
command = NULL;
|
ret = connect(sockfd,
|
||||||
if (asprintf(&command, "%llu:%s:%s", (unsigned long long)timestamp, prefix, path) < 0) {
|
(struct sockaddr *)&sun,
|
||||||
close(sockfd);
|
offsetof(struct sockaddr_un, sun_path) + strlen(SOCKET_PATH) + 1);
|
||||||
return;
|
if (ret < 0) {
|
||||||
}
|
printf("Cannot connect to %s: %s\n", SOCKET_PATH, strerror(errno));
|
||||||
write(sockfd, command, strlen(command )+1);
|
close(sockfd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
FD_ZERO(&rfds);
|
len = sizeof(cred);
|
||||||
FD_SET(sockfd, &rfds);
|
memset(&cred, 0, sizeof(cred));
|
||||||
|
ret = getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &len);
|
||||||
|
|
||||||
/* Wait up to 0.5 seconds. */
|
if (ret == 0 && cred.pid == pid) {
|
||||||
tv.tv_sec = 0;
|
printf("Recursion\n");
|
||||||
tv.tv_usec = TIMEOUT;
|
close(sockfd);
|
||||||
|
return;
|
||||||
/* if we had a timeout recently, must go quicker to avoid sequential delays */
|
}
|
||||||
if (deadtime > time(NULL)) {
|
|
||||||
tv.tv_usec = TIMEOUT2;
|
|
||||||
shorttime = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = 1;
|
command = NULL;
|
||||||
|
if (asprintf(&command, "%llu:%s:%s", (unsigned long long)timestamp, prefix, path) < 0) {
|
||||||
|
close(sockfd);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wr = write(sockfd, command, strlen(command) + 1);
|
||||||
|
|
||||||
if (!timestamp)
|
FD_ZERO(&rfds);
|
||||||
ret = select(sockfd+1, &rfds, NULL, &rfds, &tv);
|
FD_SET(sockfd, &rfds);
|
||||||
if (ret == 0 && !shorttime) {
|
|
||||||
printf("timeout for %s\n", path);
|
|
||||||
deadtime = time(NULL) + 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(sockfd);
|
/* Wait up to 0.5 seconds. */
|
||||||
|
tv.tv_sec = 0;
|
||||||
|
tv.tv_usec = TIMEOUT;
|
||||||
|
|
||||||
|
/* if we had a timeout recently, must go quicker to avoid sequential delays */
|
||||||
|
if (deadtime > time(NULL)) {
|
||||||
|
tv.tv_usec = TIMEOUT2;
|
||||||
|
shorttime = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = 1;
|
||||||
|
|
||||||
|
if (!timestamp) {
|
||||||
|
ret = select(sockfd + 1, &rfds, NULL, &rfds, &tv);
|
||||||
|
}
|
||||||
|
if (ret == 0 && !shorttime) {
|
||||||
|
printf("timeout for %s\n", path);
|
||||||
|
deadtime = time(NULL) + 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
*/
|
||||||
|
|||||||
+462
-413
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,262 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of libnica.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 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.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
*
|
||||||
|
* Ikey Doherty <michael.i.doherty@intel.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <ftw.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "files.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
#define COPY_BUFFER_SIZE 8192
|
||||||
|
|
||||||
|
DEF_AUTOFREE(DIR, closedir)
|
||||||
|
|
||||||
|
bool nc_file_exists(const char *path)
|
||||||
|
{
|
||||||
|
struct stat st = {.st_ino = 0 };
|
||||||
|
return (lstat(path, &st) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *nc_get_file_parent(const char *path)
|
||||||
|
{
|
||||||
|
autofree(char) *d = strdup(path);
|
||||||
|
char *r = realpath(dirname(d), NULL);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nc_mkdir_p(const char *path, mode_t mode)
|
||||||
|
{
|
||||||
|
autofree(char) *cl = NULL;
|
||||||
|
char *cl_base = NULL;
|
||||||
|
|
||||||
|
if (streq(path, ".") || streq(path, "/") || streq(path, "//")) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
cl = strdup(path);
|
||||||
|
cl_base = dirname(cl);
|
||||||
|
|
||||||
|
if (!nc_mkdir_p(cl_base, mode) && errno != EEXIST) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !((mkdir(path, mode) < 0 && errno != EEXIST));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nftw callback
|
||||||
|
*/
|
||||||
|
static int _rm_rf(const char *path, __attribute__((unused)) const struct stat *sb, int typeflag,
|
||||||
|
__attribute__((unused)) struct FTW *ftwbuf)
|
||||||
|
{
|
||||||
|
if (typeflag == FTW_F) {
|
||||||
|
return unlink(path);
|
||||||
|
}
|
||||||
|
return rmdir(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nc_rm_rf(const char *path)
|
||||||
|
{
|
||||||
|
bool ret = nftw(path, _rm_rf, 35, FTW_DEPTH) == 0;
|
||||||
|
|
||||||
|
sync();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nc_copy_file(const char *src, const char *dst, mode_t mode, bool remove_target)
|
||||||
|
{
|
||||||
|
int src_fd = -1;
|
||||||
|
int dest_fd = -1;
|
||||||
|
bool ret = true;
|
||||||
|
char buffer[COPY_BUFFER_SIZE] = { 0 };
|
||||||
|
int r = 0;
|
||||||
|
|
||||||
|
if (remove_target) {
|
||||||
|
if (nc_file_exists(dst) && unlink(dst) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
src_fd = open(src, O_RDONLY);
|
||||||
|
if (src_fd < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest_fd = open(dst, O_WRONLY | O_TRUNC | O_APPEND | O_CREAT, mode);
|
||||||
|
if (dest_fd < 0) {
|
||||||
|
ret = false;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if ((r = read(src_fd, &buffer, sizeof(buffer))) < 0) {
|
||||||
|
ret = false;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
if (write(dest_fd, buffer, sizeof(buffer)) != r) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = true;
|
||||||
|
end:
|
||||||
|
if (src_fd >= 0) {
|
||||||
|
close(src_fd);
|
||||||
|
}
|
||||||
|
if (dest_fd >= 0) {
|
||||||
|
close(dest_fd);
|
||||||
|
}
|
||||||
|
if (remove_target) {
|
||||||
|
sync();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following functions are taken from Ikey Doherty's goofiboot
|
||||||
|
* project
|
||||||
|
*/
|
||||||
|
char *nc_build_case_correct_path_va(const char *c, va_list ap)
|
||||||
|
{
|
||||||
|
char *p = NULL;
|
||||||
|
char *root = NULL;
|
||||||
|
struct stat st = {.st_ino = 0 };
|
||||||
|
struct dirent *ent = NULL;
|
||||||
|
|
||||||
|
p = (char *)c;
|
||||||
|
|
||||||
|
while (p) {
|
||||||
|
char *t = NULL;
|
||||||
|
char *sav = NULL;
|
||||||
|
autofree(DIR) *dirn = NULL;
|
||||||
|
|
||||||
|
if (!root) {
|
||||||
|
root = strdup(p);
|
||||||
|
} else {
|
||||||
|
sav = strdup(root);
|
||||||
|
|
||||||
|
if (!asprintf(&t, "%s/%s", root, p)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"nc_build_case_correct_path_va: Out "
|
||||||
|
"of memory\n");
|
||||||
|
va_end(ap);
|
||||||
|
if (sav) {
|
||||||
|
free(sav);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
free(root);
|
||||||
|
root = t;
|
||||||
|
t = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
autofree(char) *dirp = strdup(root);
|
||||||
|
char *dir = dirname(dirp);
|
||||||
|
|
||||||
|
if (stat(dir, &st) != 0) {
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
if (!S_ISDIR(st.st_mode)) {
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
/* Iterate the directory and find the case insensitive name,
|
||||||
|
* using
|
||||||
|
* this if it exists. Otherwise continue with the non existent
|
||||||
|
* path
|
||||||
|
*/
|
||||||
|
dirn = opendir(dir);
|
||||||
|
if (!dirn) {
|
||||||
|
goto clean;
|
||||||
|
}
|
||||||
|
while ((ent = readdir(dirn)) != NULL) {
|
||||||
|
if (strncmp(ent->d_name, ".", 1) == 0 ||
|
||||||
|
strncmp(ent->d_name, "..", 2) == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strcasecmp(ent->d_name, p) == 0) {
|
||||||
|
if (sav) {
|
||||||
|
if (!asprintf(&t, "%s/%s", sav, ent->d_name)) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"nc_build_case_"
|
||||||
|
"correct_path_va: Out "
|
||||||
|
"of memory\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
free(root);
|
||||||
|
root = t;
|
||||||
|
t = NULL;
|
||||||
|
} else {
|
||||||
|
if (root) {
|
||||||
|
sav = strdup(root);
|
||||||
|
free(root);
|
||||||
|
root = NULL;
|
||||||
|
if (!sav) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"nc_build_"
|
||||||
|
"case_correct_"
|
||||||
|
"path_va: Out "
|
||||||
|
"of memory\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
clean:
|
||||||
|
if (sav) {
|
||||||
|
free(sav);
|
||||||
|
}
|
||||||
|
p = va_arg(ap, char *);
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *nc_build_case_correct_path(const char *c, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
|
||||||
|
char *ret = NULL;
|
||||||
|
va_start(ap, c);
|
||||||
|
ret = nc_build_case_correct_path_va(c, ap);
|
||||||
|
va_end(ap);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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,95 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of libnica.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 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.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
*
|
||||||
|
* Ikey Doherty <michael.i.doherty@intel.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the given path exists in the filesystem
|
||||||
|
*
|
||||||
|
* @param path Path to the file we should check
|
||||||
|
*/
|
||||||
|
bool nc_file_exists(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the parent path for a given file
|
||||||
|
*
|
||||||
|
* @note This is an allocated string, and must be freed by the caller
|
||||||
|
* @param p Path to file
|
||||||
|
* @return a newly allocated string
|
||||||
|
*/
|
||||||
|
char *nc_get_file_parent(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively make the directories for the given path
|
||||||
|
*
|
||||||
|
* @param path Path to directory to create
|
||||||
|
* @param mode Mode to create new directories with
|
||||||
|
*
|
||||||
|
* @return A boolean value, indicating success or failure
|
||||||
|
*/
|
||||||
|
bool nc_mkdir_p(const char *path, mode_t mode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively remove the tree at @path
|
||||||
|
*
|
||||||
|
* @param path The path to remove (and all children)
|
||||||
|
*
|
||||||
|
* @return A boolean value, indicating success or failure
|
||||||
|
*/
|
||||||
|
bool nc_rm_rf(const char *path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Simple utility to copy path @src to path @dst, with mode @mode
|
||||||
|
*
|
||||||
|
* @note This will truncate the target if it exists, and does
|
||||||
|
* not preserve stat information, when @remove_target is set to true
|
||||||
|
*
|
||||||
|
* @param src Path to the source file
|
||||||
|
* @param dst Path to the destination file
|
||||||
|
* @param mode Mode of the new file when creating
|
||||||
|
* @param remove_target Whether to remove an existing target file first
|
||||||
|
*
|
||||||
|
* @return True if this succeeded
|
||||||
|
*/
|
||||||
|
bool nc_copy_file(const char *src, const char *dst, mode_t mode, bool remove_target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gradually build up a valid path, which may point within an existing
|
||||||
|
* tree, to mitigate any case sensitivity issues on case-preserving
|
||||||
|
* filesystems
|
||||||
|
*/
|
||||||
|
__attribute__((sentinel(0))) char *nc_build_case_correct_path(const char *c, ...);
|
||||||
|
|
||||||
|
char *nc_build_case_correct_path_va(const char *c, va_list ap);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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,493 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of libnica.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 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.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
*
|
||||||
|
* Ikey Doherty <michael.i.doherty@intel.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "hashmap.h"
|
||||||
|
|
||||||
|
#define INITIAL_SIZE 61
|
||||||
|
|
||||||
|
/* When we're "full", 70% */
|
||||||
|
#define FULL_FACTOR 0.7
|
||||||
|
|
||||||
|
/* Multiple to increase bucket size by */
|
||||||
|
#define INCREASE_FACTOR 4
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An bucket/chain within the hashmap
|
||||||
|
*/
|
||||||
|
typedef struct NcHashmapEntry {
|
||||||
|
void *hash; /**<The key for this item */
|
||||||
|
void *value; /**<Value for this item */
|
||||||
|
struct NcHashmapEntry *next; /**<Next item in the chain */
|
||||||
|
bool occ; /**<Whether this bucket is occupied */
|
||||||
|
} NcHashmapEntry;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A NcHashmap
|
||||||
|
*/
|
||||||
|
struct NcHashmap {
|
||||||
|
int size; /**<Current size of the hashmap */
|
||||||
|
int next_size; /**<Next size at which we need to resize */
|
||||||
|
int n_buckets; /**<Current number of buckets */
|
||||||
|
NcHashmapEntry *buckets; /**<Stores our bucket chains */
|
||||||
|
|
||||||
|
nc_hash_create_func hash; /**<Hash generation function */
|
||||||
|
nc_hash_compare_func compare; /**<Key comparison function */
|
||||||
|
nc_hash_free_func key_free; /**<Cleanup function for keys */
|
||||||
|
nc_hash_free_func value_free; /**<Cleanup function for values */
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iteration object
|
||||||
|
*/
|
||||||
|
typedef struct _NcHashmapIter {
|
||||||
|
int bucket; /**<Current bucket position */
|
||||||
|
NcHashmap *map; /**<Associated NcHashmap */
|
||||||
|
void *item; /**<Current item in this iteration */
|
||||||
|
} _NcHashmapIter;
|
||||||
|
|
||||||
|
static void nc_hashmap_update_next_size(NcHashmap *self);
|
||||||
|
static bool nc_hashmap_resize(NcHashmap *self);
|
||||||
|
|
||||||
|
static inline bool nc_hashmap_maybe_resize(NcHashmap *self)
|
||||||
|
{
|
||||||
|
if (!self) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (self->size >= self->next_size) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static NcHashmap *nc_hashmap_new_internal(nc_hash_create_func create, nc_hash_compare_func compare,
|
||||||
|
nc_hash_free_func key_free, nc_hash_free_func value_free)
|
||||||
|
{
|
||||||
|
NcHashmap *map = NULL;
|
||||||
|
NcHashmapEntry *buckets = NULL;
|
||||||
|
|
||||||
|
map = calloc(1, sizeof(NcHashmap));
|
||||||
|
if (!map) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
buckets = calloc(INITIAL_SIZE, sizeof(NcHashmapEntry));
|
||||||
|
if (!buckets) {
|
||||||
|
free(map);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
map->buckets = buckets;
|
||||||
|
map->n_buckets = INITIAL_SIZE;
|
||||||
|
map->hash = create ? create : nc_simple_hash;
|
||||||
|
map->compare = compare ? compare : nc_simple_compare;
|
||||||
|
map->key_free = key_free;
|
||||||
|
map->value_free = value_free;
|
||||||
|
map->size = 0;
|
||||||
|
|
||||||
|
nc_hashmap_update_next_size(map);
|
||||||
|
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
NcHashmap *nc_hashmap_new(nc_hash_create_func create, nc_hash_compare_func compare)
|
||||||
|
{
|
||||||
|
return nc_hashmap_new_internal(create, compare, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
NcHashmap *nc_hashmap_new_full(nc_hash_create_func create, nc_hash_compare_func compare,
|
||||||
|
nc_hash_free_func key_free, nc_hash_free_func value_free)
|
||||||
|
{
|
||||||
|
return nc_hashmap_new_internal(create, compare, key_free, value_free);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned nc_hashmap_get_hash(NcHashmap *self, const void *key)
|
||||||
|
{
|
||||||
|
unsigned hash = self->hash(key);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int nc_hashmap_insert_bucket(NcHashmap *self, NcHashmapEntry *buckets, int n_buckets,
|
||||||
|
unsigned hash, const void *key, void *value)
|
||||||
|
{
|
||||||
|
NcHashmapEntry *row = &(buckets[hash % n_buckets]);
|
||||||
|
NcHashmapEntry *head = NULL;
|
||||||
|
NcHashmapEntry *parent = head = row;
|
||||||
|
bool can_replace = false;
|
||||||
|
NcHashmapEntry *tomb = NULL;
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
while (row) {
|
||||||
|
if (!row->occ) {
|
||||||
|
tomb = row;
|
||||||
|
}
|
||||||
|
parent = row;
|
||||||
|
if (row->occ && row->hash == key) {
|
||||||
|
if (self->compare(row->hash, key)) {
|
||||||
|
can_replace = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
row = row->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (can_replace) {
|
||||||
|
/* Replace existing allocations. */
|
||||||
|
if (self->value_free) {
|
||||||
|
self->value_free(row->value);
|
||||||
|
}
|
||||||
|
if (self->key_free) {
|
||||||
|
self->key_free(row->hash);
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
} else if (tomb) {
|
||||||
|
row = tomb;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!row) {
|
||||||
|
row = calloc(1, sizeof(NcHashmapEntry));
|
||||||
|
if (!row) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
row->hash = (void *)key;
|
||||||
|
row->value = value;
|
||||||
|
row->occ = true;
|
||||||
|
if (parent != row && parent) {
|
||||||
|
parent->next = row;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nc_hashmap_put(NcHashmap *self, const void *key, void *value)
|
||||||
|
{
|
||||||
|
if (!self) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int inc;
|
||||||
|
|
||||||
|
if (nc_hashmap_maybe_resize(self)) {
|
||||||
|
if (!nc_hashmap_resize(self)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unsigned hash = nc_hashmap_get_hash(self, key);
|
||||||
|
inc = nc_hashmap_insert_bucket(self, self->buckets, self->n_buckets, hash, key, value);
|
||||||
|
if (inc > 0) {
|
||||||
|
self->size += inc;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static NcHashmapEntry *nc_hashmap_get_entry(NcHashmap *self, const void *key)
|
||||||
|
{
|
||||||
|
if (!self) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned hash = nc_hashmap_get_hash(self, key);
|
||||||
|
NcHashmapEntry *row = &(self->buckets[hash % self->n_buckets]);
|
||||||
|
|
||||||
|
while (row) {
|
||||||
|
if (self->compare(row->hash, key)) {
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
row = row->next;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void *nc_hashmap_get(NcHashmap *self, const void *key)
|
||||||
|
{
|
||||||
|
if (!self) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
NcHashmapEntry *row = nc_hashmap_get_entry(self, key);
|
||||||
|
if (row) {
|
||||||
|
return row->value;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nc_hashmap_ensure_get(NcHashmap *self, const void *key, void **value)
|
||||||
|
{
|
||||||
|
if (!self) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NcHashmapEntry *row = nc_hashmap_get_entry(self, key);
|
||||||
|
if (!row) {
|
||||||
|
*value = NULL;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*value = row->value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nc_hashmap_remove_internal(NcHashmap *self, const void *key, bool remove)
|
||||||
|
{
|
||||||
|
if (!self) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
NcHashmapEntry *row = nc_hashmap_get_entry(self, key);
|
||||||
|
|
||||||
|
if (!row) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remove) {
|
||||||
|
if (self->key_free) {
|
||||||
|
self->key_free(row->hash);
|
||||||
|
}
|
||||||
|
if (self->value_free) {
|
||||||
|
self->value_free(row->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self->size -= 1;
|
||||||
|
row->hash = NULL;
|
||||||
|
row->value = NULL;
|
||||||
|
row->occ = false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nc_hashmap_steal(NcHashmap *self, const void *key)
|
||||||
|
{
|
||||||
|
return nc_hashmap_remove_internal(self, key, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nc_hashmap_remove(NcHashmap *self, const void *key)
|
||||||
|
{
|
||||||
|
return nc_hashmap_remove_internal(self, key, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nc_hashmap_contains(NcHashmap *self, const void *key)
|
||||||
|
{
|
||||||
|
return (nc_hashmap_get(self, key)) != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void nc_hashmap_free_bucket(NcHashmap *self, NcHashmapEntry *bucket, bool nuke)
|
||||||
|
{
|
||||||
|
if (!self) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NcHashmapEntry *tmp = bucket;
|
||||||
|
NcHashmapEntry *bk = bucket;
|
||||||
|
NcHashmapEntry *root = bucket;
|
||||||
|
|
||||||
|
while (tmp) {
|
||||||
|
bk = NULL;
|
||||||
|
if (tmp->next) {
|
||||||
|
bk = tmp->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nuke && tmp->occ) {
|
||||||
|
if (self->key_free) {
|
||||||
|
self->key_free(tmp->hash);
|
||||||
|
}
|
||||||
|
if (self->value_free) {
|
||||||
|
self->value_free(tmp->value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tmp != root) {
|
||||||
|
free(tmp);
|
||||||
|
}
|
||||||
|
tmp = bk;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void nc_hashmap_free(NcHashmap *self)
|
||||||
|
{
|
||||||
|
if (!self) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < self->n_buckets; i++) {
|
||||||
|
NcHashmapEntry *row = &(self->buckets[i]);
|
||||||
|
nc_hashmap_free_bucket(self, row, true);
|
||||||
|
}
|
||||||
|
if (self->buckets) {
|
||||||
|
free(self->buckets);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void nc_hashmap_update_next_size(NcHashmap *self)
|
||||||
|
{
|
||||||
|
if (!self) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self->next_size = (int)(self->n_buckets * FULL_FACTOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nc_hashmap_size(NcHashmap *self)
|
||||||
|
{
|
||||||
|
if (!self) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return self->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool nc_hashmap_resize(NcHashmap *self)
|
||||||
|
{
|
||||||
|
if (!self || !self->buckets) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
NcHashmapEntry *old_buckets = self->buckets;
|
||||||
|
NcHashmapEntry *new_buckets = NULL;
|
||||||
|
NcHashmapEntry *entry = NULL;
|
||||||
|
int incr;
|
||||||
|
|
||||||
|
int old_size, new_size;
|
||||||
|
int items = 0;
|
||||||
|
|
||||||
|
new_size = old_size = self->n_buckets;
|
||||||
|
new_size *= INCREASE_FACTOR;
|
||||||
|
|
||||||
|
new_buckets = calloc(new_size, sizeof(NcHashmapEntry));
|
||||||
|
if (!new_buckets) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < old_size; i++) {
|
||||||
|
entry = &(old_buckets[i]);
|
||||||
|
while (entry) {
|
||||||
|
if (entry->occ) {
|
||||||
|
unsigned hash = nc_hashmap_get_hash(self, entry->hash);
|
||||||
|
if ((incr = nc_hashmap_insert_bucket(self,
|
||||||
|
new_buckets,
|
||||||
|
new_size,
|
||||||
|
hash,
|
||||||
|
entry->hash,
|
||||||
|
entry->value)) > 0) {
|
||||||
|
items += incr;
|
||||||
|
} else {
|
||||||
|
/* Likely a memory issue */
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entry = entry->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Successfully resized - do this separately because we need to
|
||||||
|
* gaurantee old data is preserved */
|
||||||
|
for (int i = 0; i < old_size; i++) {
|
||||||
|
nc_hashmap_free_bucket(self, &(old_buckets[i]), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(old_buckets);
|
||||||
|
self->n_buckets = new_size;
|
||||||
|
self->size = items;
|
||||||
|
self->buckets = new_buckets;
|
||||||
|
|
||||||
|
nc_hashmap_update_next_size(self);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
failure:
|
||||||
|
for (int i = 0; i < new_size; i++) {
|
||||||
|
nc_hashmap_free_bucket(self, &(new_buckets[i]), true);
|
||||||
|
}
|
||||||
|
free(new_buckets);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void nc_hashmap_iter_init(NcHashmap *map, NcHashmapIter *citer)
|
||||||
|
{
|
||||||
|
_NcHashmapIter *iter = NULL;
|
||||||
|
if (!map || !citer) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
iter = (_NcHashmapIter *)citer;
|
||||||
|
_NcHashmapIter it = {
|
||||||
|
.bucket = -1, .map = map, .item = NULL,
|
||||||
|
};
|
||||||
|
*iter = it;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nc_hashmap_iter_next(NcHashmapIter *citer, void **key, void **value)
|
||||||
|
{
|
||||||
|
_NcHashmapIter *iter = NULL;
|
||||||
|
NcHashmapEntry *item = NULL;
|
||||||
|
NcHashmap *map = NULL;
|
||||||
|
int n_buckets = 0;
|
||||||
|
|
||||||
|
if (!citer) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
iter = (_NcHashmapIter *)citer;
|
||||||
|
map = iter->map;
|
||||||
|
if (!map) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
n_buckets = map->n_buckets;
|
||||||
|
item = iter->item;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
if (iter->bucket >= n_buckets) {
|
||||||
|
if (item && !item->next) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!item) {
|
||||||
|
iter->bucket++;
|
||||||
|
if (iter->bucket > n_buckets - 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
item = &(map->buckets[iter->bucket]);
|
||||||
|
}
|
||||||
|
if (item) {
|
||||||
|
if (item->occ) {
|
||||||
|
goto success;
|
||||||
|
}
|
||||||
|
item = item->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
|
||||||
|
success:
|
||||||
|
iter->item = item->next;
|
||||||
|
if (key) {
|
||||||
|
*key = item->hash;
|
||||||
|
}
|
||||||
|
if (value) {
|
||||||
|
*value = item->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
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,254 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of libnica.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 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.
|
||||||
|
*
|
||||||
|
* This is a chained Hashmap implementation. It focuses on being clean
|
||||||
|
* and efficient, and is comparable (at -O2) to open addressing hashmaps
|
||||||
|
* up until around 105,000 elements, where open addressing will begin
|
||||||
|
* to come out in front. At 1 million elements, open addressing is a clear
|
||||||
|
* winner, however currently we only need a maximum of 70k elements in
|
||||||
|
* our implementation.
|
||||||
|
*
|
||||||
|
* Given the memory required to even begin to deal with 1 million elements,
|
||||||
|
* it becomes very questionable whether a hashmap should have even been
|
||||||
|
* used in the first place (mmap'd db?)
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
*
|
||||||
|
* Ikey Doherty <michael.i.doherty@intel.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
/* Convert between uint and void* */
|
||||||
|
#define NC_HASH_KEY(x) ((void *)((uintptr_t)(x)))
|
||||||
|
#define NC_HASH_VALUE(x) NC_HASH_KEY(x)
|
||||||
|
#define NC_UNHASH_KEY(x) ((unsigned int)((uintptr_t)(x)))
|
||||||
|
#define NC_UNHASH_VALUE(x) NC_UNHASH_KEY(x)
|
||||||
|
|
||||||
|
typedef struct NcHashmap NcHashmap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iteration object
|
||||||
|
*/
|
||||||
|
typedef struct NcHashmapIter {
|
||||||
|
int n0;
|
||||||
|
void *n1;
|
||||||
|
void *n2;
|
||||||
|
} NcHashmapIter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash comparison function definition
|
||||||
|
*
|
||||||
|
* @param l First value to compare
|
||||||
|
* @param r Second value to compare
|
||||||
|
*
|
||||||
|
* @return true if l and r both match, otherwise false
|
||||||
|
*/
|
||||||
|
typedef bool (*nc_hash_compare_func)(const void *l, const void *r);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash creation function definition
|
||||||
|
*
|
||||||
|
* @param key Key to generate a hash for
|
||||||
|
*
|
||||||
|
* @return an unsigned integer hash result
|
||||||
|
*/
|
||||||
|
typedef unsigned (*nc_hash_create_func)(const void *key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback definition to free keys and values
|
||||||
|
*
|
||||||
|
* @param p Single-depth pointer to either a key or value that should be freed
|
||||||
|
*/
|
||||||
|
typedef void (*nc_hash_free_func)(void *p);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default hash/comparison functions
|
||||||
|
*
|
||||||
|
* @note These are only used for comparison of *keys*, not values. Unless
|
||||||
|
* explicitly using string keys, you should most likely stick with the default
|
||||||
|
* nc_simple_hash and nc_simple_compare functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Default string hash */
|
||||||
|
static inline unsigned nc_string_hash(const void *key)
|
||||||
|
{
|
||||||
|
unsigned hash = 5381;
|
||||||
|
const signed char *c;
|
||||||
|
|
||||||
|
/* DJB's hash function */
|
||||||
|
for (c = key; *c != '\0'; c++) {
|
||||||
|
hash = (hash << 5) + hash + (unsigned)*c;
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trivial pointer->uint hash
|
||||||
|
*/
|
||||||
|
static inline unsigned nc_simple_hash(const void *source)
|
||||||
|
{
|
||||||
|
return NC_UNHASH_KEY(source);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Comparison of string keys
|
||||||
|
*/
|
||||||
|
static inline bool nc_string_compare(const void *l, const void *r)
|
||||||
|
{
|
||||||
|
if (!l || !r) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return (strcmp(l, r) == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Trivial pointer comparison
|
||||||
|
*/
|
||||||
|
static inline bool nc_simple_compare(const void *l, const void *r)
|
||||||
|
{
|
||||||
|
return (l == r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new NcHashmap
|
||||||
|
*
|
||||||
|
* @param hash Hash creation function
|
||||||
|
* @param compare Key comparison function
|
||||||
|
*
|
||||||
|
* @return A newly allocated NcHashmap
|
||||||
|
*/
|
||||||
|
NcHashmap *nc_hashmap_new(nc_hash_create_func hash, nc_hash_compare_func compare);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a new NcHashmap with cleanup functions
|
||||||
|
*
|
||||||
|
* @param hash Hash creation function
|
||||||
|
* @param compare Key comparison function
|
||||||
|
* @param key_free Function to free keys when removed/destroyed
|
||||||
|
* @param value_free Function to free values when removed/destroyed
|
||||||
|
*
|
||||||
|
* @return A newly allocated NcHashmap
|
||||||
|
*/
|
||||||
|
NcHashmap *nc_hashmap_new_full(nc_hash_create_func hash, nc_hash_compare_func compare,
|
||||||
|
nc_hash_free_func key_free, nc_hash_free_func value_free);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a key/value pair in the hashmap
|
||||||
|
*
|
||||||
|
* @note This will displace duplicate keys, and may free both the key
|
||||||
|
* and value if key_free and value_free are non null
|
||||||
|
*
|
||||||
|
* @param key Key to store in the hashmap
|
||||||
|
* @param value Value to be associated with the key
|
||||||
|
*
|
||||||
|
* @return true if the operation succeeded.
|
||||||
|
*/
|
||||||
|
bool nc_hashmap_put(NcHashmap *map, const void *key, void *value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value associated with the unique key
|
||||||
|
*
|
||||||
|
* @param key Unique key to obtain a value for
|
||||||
|
* @return The associated value if it exists, otherwise NULL
|
||||||
|
*/
|
||||||
|
void *nc_hashmap_get(NcHashmap *map, const void *key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ensure the value is definitely contained in the map and set
|
||||||
|
* the resulting pointer with it's value.
|
||||||
|
*
|
||||||
|
* @param key Unique key to obtain a value for
|
||||||
|
* @param value The associated value if it exists, otherwise NULL
|
||||||
|
*
|
||||||
|
* @returns True if the key exists, otherwise false
|
||||||
|
*/
|
||||||
|
bool nc_hashmap_ensure_get(NcHashmap *map, const void *key, void **value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if the key has an associated value in the NcHashmap
|
||||||
|
*
|
||||||
|
* @param key Unique key to check value for
|
||||||
|
* @return True if the key exists in the hashmap
|
||||||
|
*/
|
||||||
|
bool nc_hashmap_contains(NcHashmap *self, const void *key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Free the given NcHashmap, and all keys/values if appropriate
|
||||||
|
*/
|
||||||
|
void nc_hashmap_free(NcHashmap *map);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the value and key identified by key.
|
||||||
|
*
|
||||||
|
* @note If key_free or value_free are non-NULL, they will be invoked
|
||||||
|
* for both the key and value being removed
|
||||||
|
*
|
||||||
|
* @param key The unique key to remove
|
||||||
|
* @return true if the key/value pair were removed
|
||||||
|
*/
|
||||||
|
bool nc_hashmap_remove(NcHashmap *map, const void *key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the value and key identified by key without freeing them
|
||||||
|
*
|
||||||
|
* @return true if the key/value pair were stolen
|
||||||
|
*/
|
||||||
|
bool nc_hashmap_steal(NcHashmap *map, const void *key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the current size of the hashmap
|
||||||
|
*
|
||||||
|
* @return size of the current hashmap (element count)
|
||||||
|
*/
|
||||||
|
int nc_hashmap_size(NcHashmap *map);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise a NcHashmapIter for iteration purposes
|
||||||
|
*
|
||||||
|
* @note The iter *must* be re-inited to re-use, or if it becomes
|
||||||
|
* exhausted from a previous iteration run
|
||||||
|
*
|
||||||
|
* @param iter pointer to a NcHashmapIter
|
||||||
|
*/
|
||||||
|
void nc_hashmap_iter_init(NcHashmap *map, NcHashmapIter *iter);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Iterate every key/value pair in the hashmap
|
||||||
|
*
|
||||||
|
* @param iter A correctly initialised NcHashmapIter
|
||||||
|
* @param key Pointers to store the key in, may be NULL to skip
|
||||||
|
* @param value Pointer to store the value in, may be NULL to skip
|
||||||
|
*
|
||||||
|
* @return true if it's possible to iterate
|
||||||
|
*/
|
||||||
|
bool nc_hashmap_iter_next(NcHashmapIter *iter, void **key, void **value);
|
||||||
|
|
||||||
|
DEF_AUTOFREE(NcHashmap, nc_hashmap_free)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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,58 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of libnica.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2016 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.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
*
|
||||||
|
* Ikey Doherty <michael.i.doherty@intel.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define DEF_AUTOFREE(N, C) \
|
||||||
|
static inline void _autofree_func_##N(void *p) \
|
||||||
|
{ \
|
||||||
|
if (p && *(N **)p) { \
|
||||||
|
C(*(N **)p); \
|
||||||
|
(*(void **)p) = NULL; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define autofree(N) __attribute__((cleanup(_autofree_func_##N))) N
|
||||||
|
|
||||||
|
#define streq(x, y) strcmp(x, y) == 0 ? true : false
|
||||||
|
|
||||||
|
#define __nc_unused__ __attribute__((unused))
|
||||||
|
|
||||||
|
#define __nc_inline__ __attribute__((always_inline))
|
||||||
|
|
||||||
|
#define ARRAY_SIZE(x) sizeof(x) / sizeof(x[0])
|
||||||
|
|
||||||
|
DEF_AUTOFREE(char, free)
|
||||||
|
DEF_AUTOFREE(FILE, fclose)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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:
|
||||||
|
*/
|
||||||
-217
@@ -1,217 +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>
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <dirent.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <libgen.h>
|
|
||||||
|
|
||||||
#include <glib.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;
|
|
||||||
|
|
||||||
target = canonicalize_file_name(filename);
|
|
||||||
// sleep(1);
|
|
||||||
// printf("Symlink %s points to %s\n", filename, target);
|
|
||||||
unlink(filename);
|
|
||||||
link(target, filename);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void wait_for_loadavg(void)
|
|
||||||
{
|
|
||||||
FILE *file;
|
|
||||||
char line[4096];
|
|
||||||
while (1) {
|
|
||||||
double d;
|
|
||||||
file = fopen("/proc/loadavg", "r");
|
|
||||||
if (!file)
|
|
||||||
return;
|
|
||||||
line[0] = 0;
|
|
||||||
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 *fullpath1 = NULL, *fullpath2 = NULL, *dir, *dir2;
|
|
||||||
struct stat buf1, buf2;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
if (asprintf(&fullpath1, "%s%s", base1, path) < 0)
|
|
||||||
return;
|
|
||||||
if (asprintf(&fullpath2, "%s%s.tar", base2, path) < 0) {
|
|
||||||
free(fullpath1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = lstat(fullpath1, &buf1);
|
|
||||||
if (ret)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
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 (asprintf(&command, "mkdir -p %s", dir2) >= 0) {
|
|
||||||
// printf("Running -%s-\n", command);
|
|
||||||
system(command);
|
|
||||||
free(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(dir);
|
|
||||||
chdir(base1);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
system(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;
|
|
||||||
}
|
|
||||||
system(command);
|
|
||||||
free(command);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
free(fullpath1);
|
|
||||||
free(fullpath2);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void recurse_dir(char *base1, char *base2, char *path)
|
|
||||||
{
|
|
||||||
DIR *dir;
|
|
||||||
char *fullpath1, *fullpath2, *newpath;
|
|
||||||
struct dirent *entry;
|
|
||||||
|
|
||||||
fullpath1 = NULL;
|
|
||||||
fullpath2 = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
if (asprintf(&fullpath1, "%s%s", base1, path) < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
dir = opendir(fullpath1);
|
|
||||||
|
|
||||||
if (!dir) {
|
|
||||||
free(fullpath1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
while (1) {
|
|
||||||
entry = readdir(dir);
|
|
||||||
if (!entry)
|
|
||||||
break;
|
|
||||||
if (strcmp(entry->d_name, ".") == 0)
|
|
||||||
continue;
|
|
||||||
if (strcmp(entry->d_name, "..") == 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
newpath = NULL;
|
|
||||||
fullpath2 = NULL;
|
|
||||||
asprintf(&fullpath2, "%s/%s", fullpath1, entry->d_name);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
free(newpath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(dir);
|
|
||||||
free(fullpath1);
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
+542
-216
@@ -2,310 +2,636 @@
|
|||||||
* Clear Linux -- automatic debug information installation
|
* Clear Linux -- automatic debug information installation
|
||||||
*
|
*
|
||||||
* Copyright (C) 2013 Arjan van de Ven
|
* 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
|
* which in part is (C) 2012 Intel Corporation
|
||||||
* Copyright (C) 2014 Intel Corporation
|
* Copyright (C) 2014 Intel Corporation
|
||||||
*
|
*
|
||||||
* This program is free software: you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License as published by
|
||||||
* the Free Software Foundation, version 3 or later of the License.
|
* the Free Software Foundation, version 3 or later of the License.
|
||||||
*
|
*
|
||||||
* This program is distributed in the hope that it will be useful,
|
* This program is distributed in the hope that it will be useful,
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
* GNU General Public License for more details.
|
* GNU General Public License for more details.
|
||||||
*
|
*
|
||||||
* You should have received a copy of the GNU General Public License
|
* You should have received a copy of the GNU General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*
|
*
|
||||||
* Authors:
|
* Authors:
|
||||||
* Arjan van de Ven <arjanvandeven@gmail.com>
|
* Arjan van de Ven <arjanvandeven@gmail.com>
|
||||||
|
* Ikey Doherty <michael.i.doherty@intel.com>
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <grp.h>
|
||||||
|
#include <libgen.h>
|
||||||
|
#include <linux/capability.h>
|
||||||
|
#include <malloc.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stddef.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stddef.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <sys/un.h>
|
|
||||||
#include <errno.h>
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <pthread.h>
|
#include <sys/prctl.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <malloc.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "nica/files.h"
|
||||||
|
#include "nica/hashmap.h"
|
||||||
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include <glib.h>
|
|
||||||
|
|
||||||
static GMutex dupes_mutex;
|
#include "systemd/sd-daemon.h"
|
||||||
|
|
||||||
char *urls[2] = {"https://debuginfo.clearlinux.org/debuginfo/", "https://debuginfo.clearlinux.org/debuginfo/" };
|
#include "config.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_ATOMIC_SUPPORT
|
||||||
|
#include <stdatomic.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define TIMEOUT 600 /* 10 minutes */
|
||||||
|
|
||||||
|
static pthread_mutex_t dupes_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
char *urls_default[] = { "https://cdn.download.clearlinux.org/debuginfo/",
|
||||||
|
"https://cdn-alt.download.clearlinux.org/debuginfo/" };
|
||||||
|
int urls_size = 2;
|
||||||
int urlcounter = 1;
|
int urlcounter = 1;
|
||||||
|
char **urls = urls_default;
|
||||||
|
|
||||||
|
static NcHashmap *hash = NULL;
|
||||||
|
|
||||||
static GHashTable *hash;
|
#define MAX_CONNECTIONS 16
|
||||||
|
|
||||||
static int avoid_dupes(const char *url)
|
static int avoid_dupes(const char *url)
|
||||||
{
|
{
|
||||||
int retval = 0;
|
int retval = 0;
|
||||||
void *value;
|
void *value;
|
||||||
g_mutex_lock(&dupes_mutex);
|
pthread_mutex_lock(&dupes_mutex);
|
||||||
|
|
||||||
if (hash == NULL)
|
if (hash == NULL) {
|
||||||
hash = g_hash_table_new(g_str_hash, g_str_equal);
|
hash = nc_hashmap_new_full(nc_string_hash, nc_string_compare, free, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (g_hash_table_lookup_extended(hash, url, NULL, &value)) {
|
if (nc_hashmap_ensure_get(hash, url, &value)) {
|
||||||
unsigned long tm;
|
unsigned long tm;
|
||||||
tm = (unsigned long)value;
|
tm = (unsigned long)value;
|
||||||
if (time(NULL) - tm < 600) {
|
if (time(NULL) - tm < 600) {
|
||||||
retval = 1;
|
retval = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
unsigned long tm;
|
unsigned long tm;
|
||||||
tm = time(NULL);
|
tm = time(NULL);
|
||||||
void *data = (void *)(unsigned long)tm;
|
void *data = (void *)(unsigned long)tm;
|
||||||
g_hash_table_replace(hash, strdup(url), data);
|
nc_hashmap_put(hash, strdup(url), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_mutex_unlock(&dupes_mutex);
|
pthread_mutex_unlock(&dupes_mutex);
|
||||||
return retval;
|
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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current connection count atomically
|
||||||
|
*/
|
||||||
|
__nc_inline__ static inline int get_current_connection_count(void)
|
||||||
|
{
|
||||||
|
return atomic_load(¤t_connection_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment the connection counter atomically
|
||||||
|
*/
|
||||||
|
__nc_inline__ static inline void inc_connection_count(void)
|
||||||
|
{
|
||||||
|
atomic_fetch_add(¤t_connection_count, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrement the connection counter atomically
|
||||||
|
*/
|
||||||
|
__nc_inline__ static inline void dec_connection_count(void)
|
||||||
|
{
|
||||||
|
atomic_fetch_sub(¤t_connection_count, 1);
|
||||||
|
}
|
||||||
|
#else /* HAVE_ATOMIC_SUPPORT */
|
||||||
|
|
||||||
|
static int current_connection_count = 0;
|
||||||
|
|
||||||
|
/* No stdatomic compiler support, fallback to pthread mutex (slower) */
|
||||||
|
pthread_mutex_t con_count_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current connection count via mutex
|
||||||
|
*/
|
||||||
|
__nc_inline__ static inline int get_current_connection_count(void)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
pthread_mutex_lock(&con_count_mutex);
|
||||||
|
r = current_connection_count;
|
||||||
|
pthread_mutex_unlock(&con_count_mutex);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Increment the connection counter via mutex
|
||||||
|
*/
|
||||||
|
__nc_inline__ static inline void inc_connection_count(void)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&con_count_mutex);
|
||||||
|
current_connection_count++;
|
||||||
|
pthread_mutex_unlock(&con_count_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrement the connection counter via mutex
|
||||||
|
*/
|
||||||
|
__nc_inline__ static inline void dec_connection_count(void)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&con_count_mutex);
|
||||||
|
current_connection_count--;
|
||||||
|
pthread_mutex_unlock(&con_count_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* !(HAVE_ATOMIC_SUPPORT) */
|
||||||
|
|
||||||
static int curl_get_file(const char *url, const char *prefix, time_t timestamp)
|
static int curl_get_file(const char *url, const char *prefix, time_t timestamp)
|
||||||
{
|
{
|
||||||
CURLcode code;
|
CURLcode code;
|
||||||
long ret;
|
long ret;
|
||||||
int fd;
|
long changed;
|
||||||
char filename[PATH_MAX];
|
int fd;
|
||||||
CURL *curl = NULL;
|
autofree(char) *filename = NULL;
|
||||||
FILE *file;
|
CURL *curl = NULL;
|
||||||
struct stat statbuf;
|
FILE *file;
|
||||||
|
|
||||||
if (avoid_dupes(url))
|
if (avoid_dupes(url)) {
|
||||||
return 300;
|
return 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
curl = curl_easy_init();
|
||||||
|
if (curl == NULL) {
|
||||||
|
return 301;
|
||||||
|
}
|
||||||
|
|
||||||
curl = curl_easy_init();
|
// fprintf(stderr, "Fetching %s, prefix %s, path %s\n", url, prefix, path);
|
||||||
if (curl == NULL)
|
if (asprintf(&filename, "/tmp/clr-debug-info-XXXXXX") < 0) {
|
||||||
return 301;
|
curl_easy_cleanup(curl);
|
||||||
|
return 418;
|
||||||
|
}
|
||||||
|
fd = mkstemp(filename);
|
||||||
|
if (fd < 0) {
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
return 418;
|
||||||
|
}
|
||||||
|
|
||||||
|
file = fdopen(fd, "w");
|
||||||
|
|
||||||
strcpy(filename, "/tmp/clr-debug-info-XXXXXX");
|
curl_easy_setopt(curl, CURLOPT_URL, url);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
|
||||||
fd = mkstemp(filename);
|
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
|
||||||
if (fd < 0) {
|
|
||||||
curl_easy_cleanup(curl);
|
|
||||||
return 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
file = fdopen(fd, "w");
|
/*
|
||||||
|
* Some sane timeout values to prevent stalls
|
||||||
|
*
|
||||||
|
* Connect timeout is for first connection to the server.
|
||||||
|
* The low speed timeout is for slow downloads. Since many
|
||||||
|
* files are several mB large, we want to prevent them from
|
||||||
|
* taking forever. (1kB/sec avg over 30secs).
|
||||||
|
*/
|
||||||
|
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, 30);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_TIME, 30);
|
||||||
|
curl_easy_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, 1024);
|
||||||
|
|
||||||
curl_easy_setopt(curl, CURLOPT_URL, url);
|
/* request timestamp of files from server */
|
||||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
|
curl_easy_setopt(curl, CURLOPT_FILETIME, 1);
|
||||||
|
|
||||||
if (timestamp) {
|
if (timestamp) {
|
||||||
curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE);
|
curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE);
|
||||||
curl_easy_setopt(curl, CURLOPT_TIMEVALUE, timestamp);
|
curl_easy_setopt(curl, CURLOPT_TIMEVALUE, timestamp);
|
||||||
}
|
}
|
||||||
|
|
||||||
code = curl_easy_perform(curl);
|
code = curl_easy_perform(curl);
|
||||||
|
|
||||||
/* can't trust the file if we get an error back */
|
/* can't trust the file if we get an error back */
|
||||||
if (code != 0)
|
if (code != 0) {
|
||||||
unlink(filename);
|
unlink(filename);
|
||||||
|
}
|
||||||
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &ret);
|
|
||||||
fflush(file);
|
|
||||||
// printf("HTTP return code is %i\n", ret);
|
|
||||||
|
|
||||||
/* HTTP 304 is returned if (a) the cached debuginfo has the same
|
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &ret);
|
||||||
* timestamp or is newer than that on the server and (b) we haven't
|
fflush(file);
|
||||||
* already added the URL to the hash table. So, the first crash for a
|
// printf("HTTP return code is %i\n", ret);
|
||||||
* boot may result in a 304 if the debuginfo had been downloaded in a
|
|
||||||
* previous boot.
|
|
||||||
*/
|
|
||||||
if (ret != 200 && ret != 404 && ret != 304)
|
|
||||||
urlcounter++;
|
|
||||||
|
|
||||||
if (ret == 200) {
|
/* HTTP 304 is returned if (a) the cached debuginfo has the same
|
||||||
char *command = NULL;
|
* timestamp or is newer than that on the server and (b) we haven't
|
||||||
// printf("Filename is %s\n", filename);
|
* already added the URL to the hash table. So, the first crash for a
|
||||||
|
* boot may result in a 304 if the debuginfo had been downloaded in a
|
||||||
|
* previous boot.
|
||||||
|
*/
|
||||||
|
if (ret != 200 && ret != 404 && ret != 304) {
|
||||||
|
urlcounter++;
|
||||||
|
}
|
||||||
|
|
||||||
memset(&statbuf, 0, sizeof(statbuf));
|
if (ret == 200) {
|
||||||
stat(filename, &statbuf);
|
autofree(char) *command = NULL;
|
||||||
if (statbuf.st_size > 0 && asprintf(&command, "tar -C /var/cache/debuginfo/%s --no-same-owner -xf %s", prefix, filename) >= 0) {
|
struct stat statbuf;
|
||||||
system(command);
|
|
||||||
free(command);
|
/* get timestamp, if any */
|
||||||
}
|
curl_easy_getinfo(curl, CURLINFO_FILETIME, &changed);
|
||||||
}
|
if (changed >= 0) {
|
||||||
unlink(filename);
|
struct timespec times[2];
|
||||||
curl_easy_cleanup(curl);
|
times[0].tv_sec = (time_t)changed;
|
||||||
fclose(file);
|
times[0].tv_nsec = 0;
|
||||||
return ret;
|
times[1].tv_sec = (time_t)changed;
|
||||||
|
times[1].tv_nsec = 0;
|
||||||
|
futimens(fd, times);
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&statbuf, 0, sizeof(statbuf));
|
||||||
|
stat(filename, &statbuf);
|
||||||
|
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) {
|
||||||
|
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);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
double timedelta(struct timeval before, struct timeval after)
|
double timedelta(struct timeval before, struct timeval after)
|
||||||
{
|
{
|
||||||
double d;
|
double d;
|
||||||
d = 1.0 * (after.tv_sec - before.tv_sec) + (1.0 * after.tv_usec - before.tv_usec)/1000000.0;
|
d = 1.0 * (after.tv_sec - before.tv_sec) +
|
||||||
return d;
|
(1.0 * after.tv_usec - before.tv_usec) / 1000000.0;
|
||||||
|
return d;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static void *server_thread(void *arg)
|
static void *server_thread(void *arg)
|
||||||
{
|
{
|
||||||
int fd;
|
int fd = -1;
|
||||||
char buf[PATH_MAX+8];
|
char buf[PATH_MAX + 8];
|
||||||
int ret;
|
int ret;
|
||||||
char *prefix, *path, *url, *c;
|
char *prefix, *path, *c = NULL;
|
||||||
time_t timestamp;
|
autofree(char) *url = NULL;
|
||||||
struct timeval before, after;
|
time_t timestamp;
|
||||||
|
struct timeval before, after;
|
||||||
|
__nc_unused__ size_t wr = -1;
|
||||||
|
|
||||||
fd = (unsigned long)arg;
|
fd = (unsigned long)arg;
|
||||||
if (fd < 0)
|
if (fd < 0) {
|
||||||
return NULL;
|
goto thread_end;
|
||||||
|
}
|
||||||
gettimeofday(&before, NULL);
|
|
||||||
|
|
||||||
|
gettimeofday(&before, NULL);
|
||||||
|
|
||||||
memset(buf, 0, sizeof(buf));
|
memset(buf, 0, sizeof(buf));
|
||||||
ret = read(fd, buf, PATH_MAX+8);
|
ret = read(fd, buf, PATH_MAX + 8);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
close(fd);
|
goto thread_end;
|
||||||
return NULL;
|
}
|
||||||
}
|
c = strchr(buf, ':');
|
||||||
prefix = buf;
|
if (!c) {
|
||||||
c = strchr(buf, ':');
|
goto thread_end;
|
||||||
if (!c) {
|
}
|
||||||
close(fd);
|
*c = 0;
|
||||||
return NULL;
|
timestamp = strtoull(buf, NULL, 10);
|
||||||
}
|
c++;
|
||||||
*c = 0;
|
prefix = c;
|
||||||
timestamp = strtoull(buf, NULL, 10);
|
path = strchr(c, ':');
|
||||||
c++;
|
if (!path) {
|
||||||
prefix = c;
|
goto thread_end;
|
||||||
path = strchr(c, ':');
|
}
|
||||||
if (!path) {
|
*path = 0;
|
||||||
close(fd);
|
path++;
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
*path = 0;
|
|
||||||
path++;
|
|
||||||
|
|
||||||
/* GDB and elfutils both stat /usr/lib/debug directly when looking up
|
/* GDB and elfutils both stat /usr/lib/debug directly when looking up
|
||||||
* debuginfo, so avoid the download for "/.tar"; the associated cache
|
* debuginfo, so avoid the download for "/.tar"; the associated cache
|
||||||
* directories already exist by this point.
|
* directories already exist by this point.
|
||||||
*/
|
*/
|
||||||
if (strlen(path) == 1 && strcmp(path, "/") == 0) {
|
if (strlen(path) == 1 && strcmp(path, "/") == 0) {
|
||||||
close(fd);
|
goto thread_end;
|
||||||
return NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (strstr(path, "..") || strstr(prefix, "..") || strstr(path, "'") || strstr(path, ";")) {
|
if (strstr(path, "..") || strstr(prefix, "..") || strstr(path, "'") || strstr(path, ";")) {
|
||||||
close(fd);
|
goto thread_end;
|
||||||
return NULL;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (strcmp(prefix, "lib") !=0 && strcmp(prefix, "src") != 0) {
|
if (strcmp(prefix, "lib") != 0 && strcmp(prefix, "src") != 0) {
|
||||||
/* invalid prefix */
|
/* invalid prefix */
|
||||||
close(fd);
|
goto thread_end;
|
||||||
return NULL;
|
}
|
||||||
}
|
url = NULL;
|
||||||
url = NULL;
|
if (asprintf(&url, "%s%s%s.tar", urls[urlcounter % urls_size], prefix, path) < 0) {
|
||||||
if (asprintf(&url, "%s%s%s.tar", urls[urlcounter % 2], prefix, path) < 0) {
|
goto thread_end;
|
||||||
close(fd);
|
}
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
ret = curl_get_file(url, prefix, timestamp);
|
||||||
|
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case 200:
|
case 200:
|
||||||
case 300:
|
case 300:
|
||||||
case 304:
|
case 304:
|
||||||
case 404:
|
case 404:
|
||||||
// ignore these error codes
|
// ignore these error codes
|
||||||
break;
|
break;
|
||||||
default:
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
gettimeofday(&after, NULL);
|
gettimeofday(&after, NULL);
|
||||||
if (timedelta(before, after) > 0.6)
|
#if 0
|
||||||
printf("Request for %s took %5.2f seconds (%i - %i)\n", url,
|
if (timedelta(before, after) > 0.6)
|
||||||
after.tv_sec - before.tv_sec + (1.0*after.tv_usec - before.tv_usec) / 1000000.0, ret, (int)timestamp);
|
printf("Request for %s took %5.2f seconds (%i - %i)\n",
|
||||||
|
url,
|
||||||
|
after.tv_sec - before.tv_sec +
|
||||||
|
(1.0 * after.tv_usec - before.tv_usec) / 1000000.0,
|
||||||
|
ret,
|
||||||
|
(int)timestamp);
|
||||||
|
#endif
|
||||||
|
/* tell the other side we're done with the download */
|
||||||
|
wr = write(fd, "ok", 3);
|
||||||
|
|
||||||
/* tell the other side we're done with the download */
|
thread_end:
|
||||||
write(fd, "ok", 3);
|
if (fd >= 0) {
|
||||||
close(fd);
|
close(fd);
|
||||||
|
}
|
||||||
|
dec_connection_count();
|
||||||
free(url);
|
return NULL;
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int main(__nc_unused__ int argc, __nc_unused__ char **argv)
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
{
|
||||||
int sockfd;
|
int sockfd;
|
||||||
struct sockaddr_un sun;
|
struct sockaddr_un sun;
|
||||||
int ret;
|
int ret;
|
||||||
int curl_done = 0;
|
int curl_done = 0;
|
||||||
|
uid_t dbg_user = 0;
|
||||||
|
gid_t dbg_group = 0;
|
||||||
|
struct passwd *passwdentry;
|
||||||
|
const char *required_paths[] = { CACHE_DIR "/lib", CACHE_DIR "/src" };
|
||||||
|
|
||||||
if (argc < -1)
|
if (configure_urls()) {
|
||||||
(void)argv;
|
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");
|
||||||
|
if (passwdentry) {
|
||||||
|
dbg_user = passwdentry->pw_uid;
|
||||||
|
dbg_group = passwdentry->pw_gid;
|
||||||
|
}
|
||||||
|
endpwent();
|
||||||
|
|
||||||
signal(SIGPIPE,SIG_IGN);
|
if (prctl(PR_SET_DUMPABLE, 0) != 0) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Failed to disable PR_SET_DUMPABLE. Do NOT gdb attach this process: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
if (access("/var/cache/debuginfo/lib/", F_OK))
|
if (geteuid() == 0) {
|
||||||
system("mkdir -p /var/cache/debuginfo/lib/ &> /dev/null");
|
if (prctl(PR_CAPBSET_DROP, CAP_SYS_ADMIN) != 0) {
|
||||||
if (access("/var/cache/debuginfo/src/", F_OK))
|
fprintf(stderr, "Failed to drop caps: %s\n", strerror(errno));
|
||||||
system("mkdir -p /var/cache/debuginfo/src/ &> /dev/null");
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
for (size_t i = 0; i < ARRAY_SIZE(required_paths); i++) {
|
||||||
if (sockfd < 0)
|
const char *req_path = required_paths[i];
|
||||||
return EXIT_FAILURE;
|
struct stat st = { .st_ino = 0 };
|
||||||
|
if (lstat(req_path, &st) == 0) {
|
||||||
|
/* If the file already exists, check ownership
|
||||||
|
* and delete tree if incorrect. Essentially a
|
||||||
|
* one-off operation to transition from root owned to
|
||||||
|
* dbginfo owned */
|
||||||
|
if (st.st_uid == dbg_user) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "Removing old debug information %s\n", req_path);
|
||||||
|
nc_rm_rf(req_path);
|
||||||
|
}
|
||||||
|
if (!nc_mkdir_p(req_path, 00755)) {
|
||||||
|
fprintf(stderr, "Failed to mkdir: %s %s\n", strerror(errno), req_path);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
if (chown(req_path, dbg_user, dbg_group) != 0) {
|
||||||
|
fprintf(stderr, "Failed to chown: %s %s\n", strerror(errno), req_path);
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sun.sun_family = AF_UNIX;
|
signal(SIGPIPE, SIG_IGN);
|
||||||
strcpy(sun.sun_path, ":clr-debug-info");
|
|
||||||
sun.sun_path[0] = 0; /* anonymous unix socket */
|
|
||||||
|
|
||||||
ret = bind(sockfd, (struct sockaddr *)&sun, offsetof(struct sockaddr_un, sun_path) + strlen(":clr-debug-info") + 1);
|
if (sd_listen_fds(0) == 1) {
|
||||||
if (ret < 0) {
|
/* systemd socket activation */
|
||||||
printf("Failed to bind:%s \n", strerror(errno));
|
sockfd = SD_LISTEN_FDS_START + 0;
|
||||||
return EXIT_FAILURE;
|
} else if (sd_listen_fds(0) > 1) {
|
||||||
}
|
fprintf(stderr, "Too many file descriptors received.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else {
|
||||||
|
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (sockfd < 0) {
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
if (listen(sockfd, 16) < 0) {
|
sun.sun_family = AF_UNIX;
|
||||||
printf("Failed to listen:%s \n", strerror(errno));
|
strcpy(sun.sun_path, SOCKET_PATH);
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
ret = bind(sockfd,
|
||||||
|
(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);
|
||||||
|
}
|
||||||
|
|
||||||
while (1) {
|
if (listen(sockfd, 16) < 0) {
|
||||||
int clientsock;
|
fprintf(stderr, "Failed to listen:%s \n", strerror(errno));
|
||||||
pthread_t thread;
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
malloc_trim(0);
|
if (setgid(dbg_group)) {
|
||||||
clientsock = accept(sockfd, NULL, NULL);
|
fprintf(stderr, "Unable to drop privileges setgid %s\n", strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (setgroups(1, &dbg_group)) {
|
||||||
|
fprintf(stderr, "Unable to drop privileges setgroups %s\n", strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
if (setuid(dbg_user)) {
|
||||||
|
fprintf(stderr, "Unable to drop privileges setuid %s\n", strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
if (!curl_done) {
|
while (1) {
|
||||||
curl_global_init(CURL_GLOBAL_ALL);
|
fd_set rfds;
|
||||||
curl_done = 1;
|
struct timeval tv;
|
||||||
}
|
int ret;
|
||||||
|
int clientsock;
|
||||||
|
pthread_t thread;
|
||||||
|
|
||||||
pthread_create(&thread, NULL, server_thread, (void *)(unsigned long)clientsock);
|
malloc_trim(0);
|
||||||
pthread_detach(thread);
|
|
||||||
}
|
|
||||||
close(sockfd);
|
|
||||||
|
|
||||||
|
/* use select() to timeout and exit gracefully */
|
||||||
|
FD_ZERO(&rfds);
|
||||||
|
FD_SET(sockfd, &rfds);
|
||||||
|
tv.tv_sec = TIMEOUT;
|
||||||
|
tv.tv_usec = 0;
|
||||||
|
ret = select(sockfd + 1, &rfds, NULL, NULL, &tv);
|
||||||
|
if (ret == -1) {
|
||||||
|
perror("select()");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else if (ret == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
clientsock = accept(sockfd, NULL, NULL);
|
||||||
|
|
||||||
|
/* Too many connections, wait for the next loop/retry */
|
||||||
|
if (get_current_connection_count() >= MAX_CONNECTIONS) {
|
||||||
|
/* printf("Too many connections!\n"); */
|
||||||
|
shutdown(clientsock, SHUT_RDWR);
|
||||||
|
close(clientsock);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!curl_done) {
|
||||||
|
curl_global_init(CURL_GLOBAL_ALL);
|
||||||
|
curl_done = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the connection count and start the new thread */
|
||||||
|
inc_connection_count();
|
||||||
|
pthread_create(&thread, NULL, server_thread, (void *)(unsigned long)clientsock);
|
||||||
|
pthread_detach(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
*/
|
||||||
|
|||||||
@@ -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:
|
||||||
|
*/
|
||||||
@@ -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:
|
||||||
|
*/
|
||||||
Executable
+2
@@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
clang-format -i $(find . -name '*.[ch]')
|
||||||
Reference in New Issue
Block a user