Compare commits

..
78 Commits
22 .. 41
Author SHA1 Message Date
Arjan van de Ven 6f27d35886 run as nice 2017-05-08 15:40:11 +00:00
Arjan van de Ven 286069732b allow service to start early 2017-05-07 15:42:30 +00:00
Ikey Doherty 15d3176382 Bump v38 to resync configure + tags
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2017-03-09 17:48:59 +00:00
Ikey Doherty d33715f6e9 Bump v34
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2017-03-09 17:46:10 +00:00
Ikey Doherty a8dbe93c7e nica/files: Ensure we really do break on a read error
Previously nc_copy_file would return true regardless of a source read
error, flagged in analysis. Ensure we bypass the set of ret to true and
return the correct value in all instances.

Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2017-03-09 15:44:09 +00:00
Ikey Doherty ac9e0cbefb server: Remove useless assignment of prefix
This particular assignment is never used, as if this path fails, we go to
the thread end. We then reassign prefix after we split the input string.

Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2017-03-09 15:38:29 +00:00
Ikey Doherty 888d469c28 nica/hashmap: Fix signature issue & item dereference
The signature was incorrect for inserting buckets, as we used an int, not
a boolean. Another issue resolved with this change is the potential
dereferencing of a null pointer by not having checked first if item was
NULL when setting the next pointer.

Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2017-03-09 15:35:29 +00:00
Arjan van de Ven e9e16fd560 add --no-same-permissions as well 2017-03-09 14:52:37 +00:00
Auke Kok f962d43af2 Tag v33 2016-11-01 09:20:19 -07:00
Auke Kok cfacaece11 Return on error here too.
Missed a 'return' catching an error.
2016-11-01 09:15:12 -07:00
Auke Kok 96a1f7cffc Add reasonable connection timeout limits.
Adds a 30second connection timeout, and a low bandwith timeout
value (at 1kb/sec over 30 seconds) where the attempt will fail.
This provides some feedback to users that network issues are
preventing debug info from being loaded.
2016-11-01 09:15:12 -07:00
Arjan van de Ven 26c614fbe2 dumb down due to limited infra 2016-11-01 13:17:49 +00:00
Arjan van de Ven 7e694a71ab use http/2 2016-11-01 12:56:35 +00:00
Arjan van de Ven c618401317 use CDN urls 2016-11-01 12:53:04 +00:00
Arjan van de Ven c0321b2872 don't spew the journal 2016-11-01 12:52:17 +00:00
Ikey Doherty bff72b661b Release v32
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-18 19:21:20 +01:00
Ikey Doherty 4c9b2ee263 server: Disallow gdb -p attach, drop CAP_SYS_ADMIN
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-18 15:03:28 +01:00
Ikey Doherty 8cf3382343 Use correct types in absence of stdatomic.h
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-18 14:37:07 +01:00
Ikey Doherty ccbb7bb31c Use pthread mutex in the absence of stdatomic C11 atomics
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-18 14:33:26 +01:00
Ikey Doherty aacde58ece Add configure output, and check for stdatomics
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-18 14:18:56 +01:00
Ikey Doherty a6a25cbfc1 Release v31
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 17:29:35 +01:00
Ikey Doherty a54f328ad7 Fix print statements when a dir cannot be created
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 17:20:31 +01:00
Ikey Doherty 27a9b3923a Fix distcheck
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 17:16:53 +01:00
Ikey Doherty 374a17ea95 Stick myself in authors
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 17:14:47 +01:00
Ikey Doherty 80c2659731 Address unused return issues
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 17:13:41 +01:00
Ikey Doherty 6d46f4d404 Fix some warnings
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 17:07:57 +01:00
Ikey Doherty 81149b109b Make use of autofree to simplify exit conditions
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 17:03:54 +01:00
Ikey Doherty 8d9d392ce5 server: Forcibly inline functions
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 16:41:17 +01:00
Ikey Doherty 4e8854f491 server: Atomically manage a maximum connection ceiling
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 16:32:01 +01:00
Ikey Doherty 3951a29dcc Fix up some warnings
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 15:17:05 +01:00
Ikey Doherty f153d6079a fuse: Greatly simplify allocation and management of strings
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 17:08:00 +01:00
Ikey Doherty 95cd32d127 Fix last of the mkdir users
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 16:54:09 +01:00
Ikey Doherty 5d3868ad29 Get rid of mkdir calls
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 16:50:27 +01:00
Ikey Doherty a6952576e6 Use consistent file headers
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 16:43:09 +01:00
Ikey Doherty 05fd5593e2 Incorporate the nica files component
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 16:42:41 +01:00
Ikey Doherty 54918c1c02 Take care of unused variables
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 16:37:52 +01:00
Ikey Doherty e715583dc5 Drop glib entirely
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 16:34:21 +01:00
Ikey Doherty a3f4a2071c Use a hashmap to maintain memory
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 16:30:17 +01:00
Ikey Doherty 7016c88df6 Incorporate portions of libnica
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 16:18:38 +01:00
Ikey Doherty c569470df3 Use curly braces everywhere
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 15:48:34 +01:00
Ikey Doherty 883a4b0e42 Fix last commit
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 15:35:01 +01:00
Ikey Doherty a63ceb51b5 Swap GMutex for pthread_mutex_t
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 15:33:37 +01:00
Ikey Doherty b16557179c Add strict flags
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 15:22:21 +01:00
Ikey Doherty 4d1ac0e90b Apply clang-format to codebase (switching to spaces for maintainence)
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 15:20:29 +01:00
Ikey Doherty ff8275f7a1 Incorporate clang-format helpers (3.8)
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 15:20:12 +01:00
Ikey Doherty 80ae1d110c Add an autogen script
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 15:17:46 +01:00
Arjan van de Ven bba42e469e version 30 2016-02-01 14:34:27 -05:00
Patrick McCarty 13c7727a3a Bump version for release 2015-10-20 10:24:49 -07:00
Patrick McCarty 4632c932d3 Do not log for non-fatal curl errors 2015-10-20 10:17:40 -07:00
Patrick McCarty 7fcebafd08 Bump version for release
This release fixes the handling of a server HTTP 304 response, now
treating it as non-fatal.
2015-10-02 12:15:07 -07:00
Patrick McCarty 718c01f65b Treat HTTP 304 codes as non-fatal
We set the If-Modified-Since header field for each GET request, and if
the condition fails, the server will respond with HTTP 304.

The 304 means the cached debuginfo is up-to-date, not requiring a fresh
download. Since this condition is non-fatal, avoid swapping the download
URLs in this case.
2015-10-02 12:15:02 -07:00
Patrick McCarty 584cbb5b4e Update gitignore 2015-10-02 10:36:39 -07:00
Patrick McCarty 85b8895e15 Bump version for release
This release fixes some compiler warnings and the distcheck target, and
addresses a recurrent 404 issue by avoiding a download attempt for
".tar" from the root debuginfo directory.
2015-09-29 12:32:23 -07:00
Patrick McCarty de08f0ebd5 Avoid attempt to download {lib,src}/debug
The associated cache directories in /var/cache/debuginfo/{lib,src}
already exist, and the tar for / is not created on the server, so avoid
downloading it altogether.
2015-09-29 12:25:13 -07:00
Patrick McCarty b51f835219 Refresh version in configure.ac
The configure.ac version was falling behind the tagged version...
2015-09-28 14:02:03 -07:00
Patrick McCarty 905e8051b2 Fix distcheck target
Adding two --with-* configure options for the systemd pkgconfig-defined
variables gives opportunity for distcheck to succeed; the variables use
hardcoded paths to /usr/lib/systemd/... without a PREFIX, so the paths
need to be relocated to $dc_install_base, a variable distcheck uses for
the normal variables that begin with PREFIX.
2015-09-28 13:52:24 -07:00
Patrick McCarty 19652c9c87 Convert server to use modern Glib Thread API
Using a GStaticMutex and associated functions are deprecated, since
a GMutex can be statically allocated now (as of glib 2.32).
2015-09-25 14:20:22 -07:00
Patrick McCarty a524875fd3 Update gitignore 2015-09-25 14:19:56 -07:00
Patrick McCarty 91efece071 Fix build warning for implicitly included header 2015-09-25 14:00:33 -07:00
Arjan van de Ven 37048557ec https 2015-07-20 23:02:09 -04:00
Arjan van de Ven d2192337d0 default to the other server for now 2015-04-24 17:55:53 -04:00
Arjan van de Ven 0642cc1835 implement multi-url setup 2015-03-23 14:45:00 -04:00
Arjan van de Ven 77fc03de73 move logging up 2015-03-23 14:37:26 -04:00
Arjan van de Ven 97c6ab80a0 better logging 2015-03-23 14:17:30 -04:00
Arjan van de Ven aeb73c71d3 few more checks 2015-03-23 14:15:42 -04:00
Arjan van de Ven a64fc31838 put memory optimizations back 2015-03-23 14:12:31 -04:00
Arjan van de Ven 8d6503ed2f Revert "Wait with curl init until the first connection comes in"
This reverts commit 6fb3c6f193.
2015-03-05 18:00:06 -05:00
Arjan van de Ven 6fb3c6f193 Wait with curl init until the first connection comes in
this should save a bunch of memory for the common case
2015-02-16 18:12:45 -05:00
Dimitri John Ledkov 3124367ce7 clr-debug-info: Use well known install paths.
systemd pkgconfig module is already required, which will have system
paths defined as pkg-config variables. This simplifies autofoo, and
installs tmpfile.d into a system location under /usr, rather than
admin location under /etc.
2015-02-02 10:30:49 +00:00
Arjan van de Ven 41e3538eb4 use the non-staging URL 2015-01-31 13:48:44 -05:00
avandeve b199c54804 version 11 2014-12-26 11:28:04 -05:00
avandeve 6009fe08f7 don't "system" unless it's really really needed 2014-12-26 11:26:36 -05:00
avandeve 2cd799e5ec one more typo 2014-12-26 10:48:24 -05:00
avandeve c3701ee088 make systemd not complain 2014-12-26 10:32:42 -05:00
avandeve 8b995e1a20 move the cache dir to /var/cache
for proper stateless operation
2014-12-26 10:32:05 -05:00
avandeve c4e73a4c9e release 8 2014-12-25 19:29:02 -05:00
avandeve b5ab4c61e8 XFS does nto support DT_DIR 2014-12-26 00:15:36 -05:00
avandeve eb6b1b86a3 Initial Import from Fenrus Linux 2014-12-25 23:53:41 -05:00
17 changed files with 2357 additions and 833 deletions
+84
View File
@@ -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
...
+7
View File
@@ -22,3 +22,10 @@ stamp-h1
*.tar.gz *.tar.gz
tags tags
cscope.* cscope.*
*.la
*.lo
.libs/
config.guess
config.sub
libtool
ltmain.sh
+28 -4
View File
@@ -4,19 +4,43 @@ 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)
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 clr_debug_prepare bin_PROGRAMS = clr_debug_fuse clr_debug_daemon 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 = \
-pthread \
$(AM_CFLAGS)
clr_debug_prepare_SOURCES = src/prepare.c clr_debug_prepare_SOURCES = src/prepare.c
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
clr_debug_daemon_LDADD = $(glib_LIBS) ${curl_LIBS} clr_debug_prepare_LDADD = libnica.la
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
Executable
+14
View File
@@ -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
+2
View File
@@ -4,6 +4,8 @@ Description=Clear Linux debuginfo daemon
[Service] [Service]
Type=simple Type=simple
ExecStart=/usr/bin/clr_debug_daemon ExecStart=/usr/bin/clr_debug_daemon
DefaultDependencies=no
Nice=10
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
+2
View File
@@ -5,6 +5,8 @@ After=clr_debug_daemon.service
[Service] [Service]
Type=simple Type=simple
ExecStart=/usr/bin/clr_debug_fuse ExecStart=/usr/bin/clr_debug_fuse
DefaultDependencies=no
Nice=10
[Install] [Install]
WantedBy=multi-user.target WantedBy=multi-user.target
+29 -2
View File
@@ -2,16 +2,16 @@
# 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, 22, arjan@linux.intel.com) AC_INIT(clr-debug-info, 38, 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
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])
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])
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 +27,32 @@ 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
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}
C11 stdatomic support: ${have_atomics}
])
+73 -66
View File
@@ -7,32 +7,34 @@
* 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>
/* 0.75 seconds timeout */ /* 0.75 seconds timeout */
#define TIMEOUT 750000 #define TIMEOUT 750000
@@ -45,71 +47,76 @@ 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, ":clr-debug-info");
close(sockfd); sun.sun_path[0] = 0; /* anonymous unix socket */
}
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(":clr-debug-info") + 1);
return; if (ret < 0) {
} printf("Cannot connect %s\n", 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);
} }
+439 -413
View File
File diff suppressed because it is too large Load Diff
+262
View File
@@ -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:
*/
+95
View File
@@ -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:
*/
+493
View File
@@ -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:
*/
+254
View File
@@ -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:
*/
+58
View File
@@ -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:
*/
+167 -141
View File
@@ -9,209 +9,235 @@
* 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 <dirent.h>
#include <errno.h>
#include <libgen.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/types.h> #include <sys/socket.h>
#include <dirent.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <libgen.h> #include <sys/types.h>
#include <sys/types.h>
#include <sys/un.h>
#include <unistd.h>
#include <glib.h> #include "nica/files.h"
/* /*
this program takes a directory /var/www/html/debuginfo.raw, this program takes a directory /var/www/html/debuginfo.raw,
in which all debuginfo rpms have previously been rpm2cpio'd, and in which all debuginfo rpms have previously been rpm2cpio'd, and
creates the content for /var/www/html/debuginfo creates the content for /var/www/html/debuginfo
which contains tar'd up/compressed versions of all the files. which contains tar'd up/compressed versions of all the files.
As part of this symlinks will be resolved server side As part of this symlinks will be resolved server side
as much as possible. as much as possible.
*/ */
static void unsymlink(char *filename) static void unsymlink(char *filename)
{ {
char *target; char *target;
__nc_unused__ int r;
target = canonicalize_file_name(filename); target = canonicalize_file_name(filename);
// sleep(1); // sleep(1);
// printf("Symlink %s points to %s\n", filename, target); // printf("Symlink %s points to %s\n", filename, target);
unlink(filename); unlink(filename);
link(target, filename); r = link(target, filename);
} }
static void wait_for_loadavg(void) static void wait_for_loadavg(void)
{ {
FILE *file; FILE *file;
char line[4096]; char line[4096];
while (1) { __nc_unused__ char *ret = NULL;
double d;
file = fopen("/proc/loadavg", "r"); while (1) {
if (!file) double d;
return; file = fopen("/proc/loadavg", "r");
line[0] = 0; if (!file) {
fgets(line, 4096, file); return;
fclose(file); }
d = strtod(line, NULL); line[0] = 0;
if (d < 50) ret = fgets(line, 4096, file);
return; fclose(file);
sleep(5); d = strtod(line, NULL);
if (d < 50) {
} return;
}
sleep(5);
}
} }
int tarcount; int tarcount;
static void do_one_file(char *base1, char *base2, char *path, int isdir) static void do_one_file(char *base1, char *base2, char *path, int isdir)
{ {
char *fullpath1 = NULL, *fullpath2 = NULL, *dir, *dir2; char *dir2 = NULL;
struct stat buf1, buf2; autofree(char) * fullpath1, *fullpath2, *dir = NULL;
int ret; struct stat buf1, buf2;
int ret;
int sret;
if (asprintf(&fullpath1, "%s%s", base1, path) < 0) if (asprintf(&fullpath1, "%s%s", base1, path) < 0) {
return; return;
if (asprintf(&fullpath2, "%s%s.tar", base2, path) < 0) { }
free(fullpath1); if (asprintf(&fullpath2, "%s%s.tar", base2, path) < 0) {
return; return;
} }
ret = lstat(fullpath1, &buf1); ret = lstat(fullpath1, &buf1);
if (ret) if (ret) {
goto out; return;
}
if (S_ISLNK(buf1.st_mode)) { if (S_ISLNK(buf1.st_mode)) {
// printf("%s is a symlink\n", fullpath1); // printf("%s is a symlink\n", fullpath1);
ret = stat(fullpath1, &buf2); ret = stat(fullpath1, &buf2);
if (!ret) if (!ret) {
unsymlink(fullpath1); unsymlink(fullpath1);
ret = lstat(fullpath1, &buf1); }
} ret = lstat(fullpath1, &buf1);
}
ret = lstat(fullpath2, &buf2); ret = lstat(fullpath2, &buf2);
if (ret || buf1.st_mtime > buf2.st_mtime) { if (ret || buf1.st_mtime > buf2.st_mtime) {
char *command = NULL; char *command = NULL;
unlink(fullpath2); unlink(fullpath2);
dir = strdup(fullpath2); dir = strdup(fullpath2);
dir2 = dirname(dir); dir2 = dirname(dir);
if (asprintf(&command, "mkdir -p %s", dir2) >= 0) { if (dir2) {
// printf("Running -%s-\n", command); (void)nc_mkdir_p(dir2, 00755);
system(command); }
free(command);
}
free(dir); if (chdir(base1) != 0) {
chdir(base1); fprintf(stderr, "Failed to chdir: %s\n", strerror(errno));
if (!isdir && asprintf(&command, "tar --no-recursion -C %s -Jcf %s %s &", base1, fullpath2, path) >= 0) { return;
// 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) { if (!isdir &&
// printf("Running -%s-\n", command); asprintf(&command,
printf("Processing %s\n", fullpath2); "tar --no-recursion -C %s -Jcf %s %s &",
tarcount++; base1,
if (tarcount > 50) { fullpath2,
wait_for_loadavg(); path) >= 0) {
tarcount = 0; // printf("Running -%s-\n", command);
} printf("Processing %s\n", fullpath2);
system(command); tarcount++;
free(command); if (tarcount > 50) {
} wait_for_loadavg();
tarcount = 0;
} }
if ((sret = system(command)) != 0) {
fprintf(stderr, "Failure in command: [%d] %s\n", sret, command);
}
free(command);
}
out: if (isdir &&
free(fullpath1); asprintf(&command,
free(fullpath2); "tar --no-recursion -C %s -Jcf %s `find %s -type d` `find %s "
"-maxdepth 1 -type l` &",
base1,
fullpath2,
path,
path) >= 0) {
// printf("Running -%s-\n", command);
printf("Processing %s\n", fullpath2);
tarcount++;
if (tarcount > 50) {
wait_for_loadavg();
tarcount = 0;
}
if ((sret = system(command)) != 0) {
fprintf(stderr, "Failure in command: [%d] %s\n", sret, command);
}
free(command);
}
}
} }
static void recurse_dir(char *base1, char *base2, char *path) static void recurse_dir(char *base1, char *base2, char *path)
{ {
DIR *dir; DIR *dir;
char *fullpath1, *fullpath2, *newpath; char *fullpath1 = NULL;
struct dirent *entry; struct dirent *entry;
fullpath1 = NULL; if (asprintf(&fullpath1, "%s%s", base1, path) < 0) {
fullpath2 = NULL; return;
}
dir = opendir(fullpath1);
if (asprintf(&fullpath1, "%s%s", base1, path) < 0) if (!dir) {
return; return;
}
dir = opendir(fullpath1); while (1) {
autofree(char) *fullpath2 = NULL;
autofree(char) *newpath = NULL;
if (!dir) { entry = readdir(dir);
free(fullpath1); if (!entry) {
return; break;
} }
while (1) { if (strcmp(entry->d_name, ".") == 0) {
entry = readdir(dir); continue;
if (!entry) }
break; if (strcmp(entry->d_name, "..") == 0) {
if (strcmp(entry->d_name, ".") == 0) continue;
continue; }
if (strcmp(entry->d_name, "..") == 0)
continue; newpath = NULL;
fullpath2 = NULL;
newpath = NULL; if (asprintf(&fullpath2, "%s/%s", fullpath1, entry->d_name) < 0) {
fullpath2 = NULL; return;
asprintf(&fullpath2, "%s/%s", fullpath1, entry->d_name); }
if (asprintf(&newpath, "%s/%s", path, entry->d_name) >= 0) { if (asprintf(&newpath, "%s/%s", path, entry->d_name) >= 0) {
struct stat sb; struct stat sb;
stat(fullpath2, &sb); stat(fullpath2, &sb);
if (entry->d_type == DT_DIR || S_ISDIR(sb.st_mode)) { if (entry->d_type == DT_DIR || S_ISDIR(sb.st_mode)) {
do_one_file(base1, base2, newpath, 1); do_one_file(base1, base2, newpath, 1);
recurse_dir(base1, base2, newpath); recurse_dir(base1, base2, newpath);
} else { } else {
do_one_file(base1, base2, newpath, 0); do_one_file(base1, base2, newpath, 0);
} }
free(newpath); }
} }
} closedir(dir);
closedir(dir);
free(fullpath1);
} }
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
if (argc < 0) if (argc < 0)
(void)argv; (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/lib/debug/",
recurse_dir("/var/www/html/debuginfo.raw/usr/src/debug/", "/var/www/html/debuginfo/src/", "."); "/var/www/html/debuginfo/lib/",
".");
recurse_dir("/var/www/html/debuginfo.raw/usr/src/debug/",
"/var/www/html/debuginfo/src/",
".");
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
+348 -207
View File
@@ -9,294 +9,435 @@
* 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 <linux/capability.h>
#include <malloc.h>
#include <pthread.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 "config.h"
char *urls[2] = {"https://debuginfo.clearlinux.org/debuginfo/", "http://debuginfo.fenrus.org/debuginfo/" }; #ifdef HAVE_ATOMIC_SUPPORT
#include <stdatomic.h>
#endif
static pthread_mutex_t dupes_mutex = PTHREAD_MUTEX_INITIALIZER;
char *urls[2] = { "https://cdn.download.clearlinux.org/debuginfo/",
"https://cdn.download.clearlinux.org/debuginfo/" };
int urlcounter = 1; int urlcounter = 1;
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;
} }
#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(&current_connection_count);
}
/**
* Increment the connection counter atomically
*/
__nc_inline__ static inline void inc_connection_count(void)
{
atomic_fetch_add(&current_connection_count, 1);
}
/**
* Decrement the connection counter atomically
*/
__nc_inline__ static inline void dec_connection_count(void)
{
atomic_fetch_sub(&current_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; int fd;
char filename[PATH_MAX]; char filename[PATH_MAX];
CURL *curl = NULL; CURL *curl = NULL;
FILE *file; FILE *file;
struct stat statbuf; struct stat statbuf;
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(); strcpy(filename, "/tmp/clr-debug-info-XXXXXX");
if (curl == NULL)
return 301;
fd = mkstemp(filename);
if (fd < 0) {
curl_easy_cleanup(curl);
return 500;
}
strcpy(filename, "/tmp/clr-debug-info-XXXXXX"); file = fdopen(fd, "w");
fd = mkstemp(filename);
if (fd < 0) {
curl_easy_cleanup(curl);
return 500;
}
file = fdopen(fd, "w"); curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
curl_easy_setopt(curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2_0);
curl_easy_setopt(curl, CURLOPT_URL, url); /*
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file); * 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);
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) { // printf("Filename is %s\n", filename);
system(command);
free(command); memset(&statbuf, 0, sizeof(statbuf));
} stat(filename, &statbuf);
} if (statbuf.st_size > 0 &&
unlink(filename); asprintf(&command,
curl_easy_cleanup(curl); "tar -C /var/cache/debuginfo/%s --no-same-owner --no-same-permissions -xf %s",
fclose(file); prefix,
return ret; filename) >= 0) {
if (system(command) != 0) {
fputs("Warning: tar extraction failed\n", stderr);
}
}
}
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 % 2], 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);
if (ret != 200) switch (ret) {
printf("Request for %s resulted in error %i\n", url, ret); case 200:
case 300:
case 304:
case 404:
// ignore these error codes
break;
default:
printf("Request for %s resulted in error %i\n", url, ret);
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;
const char *required_paths[] = { "/var/cache/debuginfo/lib", "/var/cache/debuginfo/src" };
if (argc < -1) if (prctl(PR_SET_DUMPABLE, 0) != 0) {
(void)argv; fprintf(stderr,
"Failed to disable PR_SET_DUMPABLE. Do NOT gdb attach this process: %s\n",
strerror(errno));
}
if (geteuid() == 0) {
if (prctl(PR_CAPBSET_DROP, CAP_SYS_ADMIN) != 0) {
fprintf(stderr, "Failed to drop caps: %s\n", strerror(errno));
}
}
signal(SIGPIPE,SIG_IGN); for (size_t i = 0; i < ARRAY_SIZE(required_paths); i++) {
const char *req_path = required_paths[i];
if (nc_file_exists(req_path)) {
continue;
}
if (!nc_mkdir_p(req_path, 00755)) {
fprintf(stderr, "Failed to mkdir: %s %s\n", strerror(errno), req_path);
return EXIT_FAILURE;
}
}
if (access("/var/cache/debuginfo/lib/", F_OK)) signal(SIGPIPE, SIG_IGN);
system("mkdir -p /var/cache/debuginfo/lib/ &> /dev/null");
if (access("/var/cache/debuginfo/src/", F_OK))
system("mkdir -p /var/cache/debuginfo/src/ &> /dev/null");
sockfd = socket(AF_UNIX, SOCK_STREAM, 0); sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) if (sockfd < 0) {
return EXIT_FAILURE; return EXIT_FAILURE;
}
sun.sun_family = AF_UNIX; sun.sun_family = AF_UNIX;
strcpy(sun.sun_path, ":clr-debug-info"); strcpy(sun.sun_path, ":clr-debug-info");
sun.sun_path[0] = 0; /* anonymous unix socket */ 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); ret = bind(sockfd,
if (ret < 0) { (struct sockaddr *)&sun,
printf("Failed to bind:%s \n", strerror(errno)); offsetof(struct sockaddr_un, sun_path) + strlen(":clr-debug-info") + 1);
return EXIT_FAILURE; if (ret < 0) {
} printf("Failed to bind:%s \n", strerror(errno));
return EXIT_FAILURE;
}
if (listen(sockfd, 16) < 0) { if (listen(sockfd, 16) < 0) {
printf("Failed to listen:%s \n", strerror(errno)); printf("Failed to listen:%s \n", strerror(errno));
return EXIT_FAILURE; return EXIT_FAILURE;
} }
while (1) {
int clientsock;
pthread_t thread;
while (1) { malloc_trim(0);
int clientsock; clientsock = accept(sockfd, NULL, NULL);
pthread_t thread;
malloc_trim(0); /* Too many connections, wait for the next loop/retry */
clientsock = accept(sockfd, NULL, NULL); if (get_current_connection_count() >= MAX_CONNECTIONS) {
/* printf("Too many connections!\n"); */
shutdown(clientsock, SHUT_RDWR);
close(clientsock);
continue;
}
if (!curl_done) { if (!curl_done) {
curl_global_init(CURL_GLOBAL_ALL); curl_global_init(CURL_GLOBAL_ALL);
curl_done = 1; curl_done = 1;
} }
pthread_create(&thread, NULL, server_thread, (void *)(unsigned long)clientsock); /* Update the connection count and start the new thread */
pthread_detach(thread); inc_connection_count();
} pthread_create(&thread, NULL, server_thread, (void *)(unsigned long)clientsock);
close(sockfd); pthread_detach(thread);
}
if (hash) {
nc_hashmap_free(hash);
}
close(sockfd);
} }
+2
View File
@@ -0,0 +1,2 @@
#!/bin/bash
clang-format -i $(find . -name '*.[ch]')