Compare commits

..
74 Commits
13 .. 44
Author SHA1 Message Date
Arjan van de Ven d20d585e5c much shorter timeouts 2017-12-10 14:25:07 +00:00
Icarus Sparry 1f3a0f0be4 Extract tar file as dbginfo
Make /var/cache/debuginfo and its contents owned by dgbinfo. Create
the directories as this user, and switch to run as this user.

Signed-off-by: Icarus Sparry <icarus.w.sparry@intel.com>
2017-10-31 13:35:29 -07:00
Icarus Sparry d2d67bdb1d Change tmpfiles.d configuration
Use the dbginfo user for the directories.

Signed-off-by: Icarus Sparry <icarus.w.sparry@intel.com>
2017-10-31 09:47:39 -07:00
Auke Kok 60db7bab0f v43 2017-06-06 13:28:11 -07:00
Auke Kok ef6b11498a DefaultDependencies keyword is only valid in [Unit] context. 2017-06-06 13:27:20 -07:00
Auke Kok efeed3e83f v42. 2017-06-01 16:22:00 -07:00
Auke Kok f5542e7fbb Fetch timestamp from debuginfo server.
We trigger redownloads from the server if the timestamp of
downloaded tar files is too new. An easy way around this issue
is to request the timestamp from the server instead of using
the download time. A `touch` of the tar then assures that
the downloaded file has the same timestamp as the server has.
2017-06-01 16:19:15 -07:00
Arjan van de Ven be8a99da53 allow service to start early 2017-05-07 15:42:30 +00:00
Ikey Doherty c9304402e2 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 6e202f13f7 Bump v34
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2017-03-09 17:46:10 +00:00
Ikey Doherty 6735f8f6ed 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 8b3777ab99 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 84350939ef 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 72b1120a40 add --no-same-permissions as well 2017-03-09 14:52:37 +00:00
Auke Kok d3d5fab301 Tag v33 2016-11-01 09:20:19 -07:00
Auke Kok e377433a9d Return on error here too.
Missed a 'return' catching an error.
2016-11-01 09:15:12 -07:00
Auke Kok afa92c77b1 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 a01ce4c329 dumb down due to limited infra 2016-11-01 13:17:49 +00:00
Arjan van de Ven 1eaaac582c use http/2 2016-11-01 12:56:35 +00:00
Arjan van de Ven 935dbee3c7 use CDN urls 2016-11-01 12:53:04 +00:00
Arjan van de Ven 0065ef2670 don't spew the journal 2016-11-01 12:52:17 +00:00
Ikey Doherty b5b4030f7c Release v32
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-18 19:21:20 +01:00
Ikey Doherty de9e0ce5c5 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 9e400bd149 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 f5a65358af 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 c82a007960 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 02ece110b5 Release v31
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 17:29:35 +01:00
Ikey Doherty 3a6bf4a167 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 fc61591870 Fix distcheck
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 17:16:53 +01:00
Ikey Doherty 2f26fc55c7 Stick myself in authors
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 17:14:47 +01:00
Ikey Doherty dfff530803 Address unused return issues
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 17:13:41 +01:00
Ikey Doherty 9685fcb632 Fix some warnings
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 17:07:57 +01:00
Ikey Doherty 14495e064b 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 7b64fb601d server: Forcibly inline functions
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 16:41:17 +01:00
Ikey Doherty b24d93fe3d 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 5b7c484b64 Fix up some warnings
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-17 15:17:05 +01:00
Ikey Doherty d23b8e17bd 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 b120d1c38f 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 bbc34ad790 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 caf84d9b5f Use consistent file headers
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 16:43:09 +01:00
Ikey Doherty bc276b4920 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 78485dc583 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 ce02c64c0c Drop glib entirely
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 16:34:21 +01:00
Ikey Doherty f272c08d4f 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 3babbe4b7b Incorporate portions of libnica
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 16:18:38 +01:00
Ikey Doherty aad87bbdc1 Use curly braces everywhere
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 15:48:34 +01:00
Ikey Doherty 4505d32c68 Fix last commit
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 15:35:01 +01:00
Ikey Doherty 67a9735acb 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 1c043d5bd7 Add strict flags
Signed-off-by: Ikey Doherty <michael.i.doherty@intel.com>
2016-05-11 15:22:21 +01:00
Ikey Doherty 8c01f4012f 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 955c1b7e99 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 a92e6f386a 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 670069d659 version 30 2016-02-01 14:34:27 -05:00
Patrick McCarty be74f893e6 Bump version for release 2015-10-20 10:24:49 -07:00
Patrick McCarty 7a5e4a9acd Do not log for non-fatal curl errors 2015-10-20 10:17:40 -07:00
Patrick McCarty 07a4c3d305 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 ab0e59628f 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 af4a3f64f0 Update gitignore 2015-10-02 10:36:39 -07:00
Patrick McCarty 8c65e96479 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 7ea9a50b19 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 e16ab76926 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 090cb27a34 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 cbaf943fca 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 32ae400e7d Update gitignore 2015-09-25 14:19:56 -07:00
Patrick McCarty 82f03f8e22 Fix build warning for implicitly included header 2015-09-25 14:00:33 -07:00
Arjan van de Ven c1f45d9f3c https 2015-07-20 23:02:09 -04:00
Arjan van de Ven bcff8fae39 default to the other server for now 2015-04-24 17:55:53 -04:00
Arjan van de Ven 66bab25bcd implement multi-url setup 2015-03-23 14:45:00 -04:00
Arjan van de Ven 49ac392f01 move logging up 2015-03-23 14:37:26 -04:00
Arjan van de Ven 71f4e789c4 better logging 2015-03-23 14:17:30 -04:00
Arjan van de Ven f776162882 few more checks 2015-03-23 14:15:42 -04:00
Arjan van de Ven a2abd8d2a9 put memory optimizations back 2015-03-23 14:12:31 -04:00
Arjan van de Ven 8844b0b0e1 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 ca63e1be25 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
18 changed files with 2443 additions and 816 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
...
+11
View File
@@ -4,10 +4,12 @@ clr_debug_fuse
clr_debug_daemon
clr_debug_prepare
.deps/
.dirstamp
Makefile
Makefile.in
aclocal.m4
autom4te.cache/
compile
config.h
config.h.in
config.log
@@ -18,3 +20,12 @@ install-sh
missing
stamp-h1
*.tar.gz
tags
cscope.*
*.la
*.lo
.libs/
config.guess
config.sub
libtool
ltmain.sh
+32 -4
View File
@@ -1,18 +1,46 @@
EXTRA_DIST = COPYING clr_debug_fuse.service clr_debug_daemon.service debuginfo.conf
DISTCHECK_CONFIGURE_FLAGS = \
--with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) \
--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
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_daemon_SOURCES = src/server.c
clr_debug_daemon_CFLAGS = \
-pthread \
$(AM_CFLAGS)
clr_debug_prepare_SOURCES = src/prepare.c
AM_CPPFLAGS = $(AM_CFLAGS) $(glib_CFLAGS) ${curl_CFLAGS} ${fuse_CFLAGS}
clr_debug_fuse_LDADD = ${fuse_LIBS} $(glib_LIBS)
clr_debug_daemon_LDADD = $(glib_LIBS) ${curl_LIBS}
clr_debug_prepare_LDADD = $(glib_LIBS)
clr_debug_fuse_LDADD = ${fuse_LIBS} libnica.la
clr_debug_daemon_LDADD = ${curl_LIBS} libnica.la
clr_debug_prepare_LDADD = libnica.la
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
+1
View File
@@ -1,5 +1,6 @@
[Unit]
Description=Clear Linux debuginfo daemon
DefaultDependencies=no
[Service]
Type=simple
+1
View File
@@ -1,6 +1,7 @@
[Unit]
Description=Clear Linux debuginfo fuse monitor
After=clr_debug_daemon.service
DefaultDependencies=no
[Service]
Type=simple
+41 -6
View File
@@ -2,22 +2,57 @@
# Process this file with autoconf to produce a configure script.
AC_PREREQ([2.66])
AC_INIT(clr-debug-info, 11, arjan@linux.intel.com)
AC_INIT(clr-debug-info, 43, arjan@linux.intel.com)
AM_INIT_AUTOMAKE([foreign -Wall -W subdir-objects])
AM_SILENT_RULES([yes])
AC_PROG_CC
AC_LANG(C)
AC_CONFIG_HEADERS([config.h])
PKG_CHECK_MODULES([glib], [glib-2.0 gthread-2.0])
PKG_CHECK_MODULES([curl], [libcurl])
PKG_CHECK_MODULES([fuse], [fuse])
PKG_CHECK_MODULES([SYSTEMD], [systemd])
LT_INIT
tmpfilesdir=`pkg-config --variable tmpfilesdir systemd`
AC_SUBST(tmpfilesdir)
dir=""
AC_ARG_WITH([systemdsystemunitdir], AS_HELP_STRING([--with-systemdsystemunitdir=DIR],
[path to systemd system service dir @<:@default=/usr/lib/systemd/system@:>@]), [dir=${withval}],
[dir="$($PKG_CONFIG --variable=systemdsystemunitdir systemd)"])
test -z "${dir}" && dir=/usr/lib/systemd/system
AC_SUBST(systemdsystemunitdir, [${dir}])
systemdsystemunitdir=`pkg-config --variable systemdsystemunitdir systemd`
AC_SUBST(systemdsystemunitdir)
dir=""
AC_ARG_WITH([systemdtmpfilesdir], AS_HELP_STRING([--with-systemdtmpfilesdir=DIR],
[path to systemd tmpfiles dir @<:@default=/usr/lib/tmpfiles.d@:>@]), [dir=${withval}],
[dir="$($PKG_CONFIG --variable=tmpfilesdir systemd)"])
test -z "${dir}" && dir=/usr/lib/tmpfiles.d
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_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}
])
+4 -2
View File
@@ -8,5 +8,7 @@
# See tmpfiles.d(5) for details
# Clear tmp directories separately, to make them easier to override
d /var/cache/debuginfo/lib 755 root root 10d
d /var/cache/debuginfo/src 755 root root 1d
# Unfortunatly tmpfiles doesn't change the ownership for things if they
# are not listed.
d /var/cache/debuginfo/lib 755 dbginfo dbginfo 10d
d /var/cache/debuginfo/src 755 dbginfo dbginfo 1d
+75 -68
View File
@@ -7,36 +7,38 @@
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 or later of the License.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Arjan van de Ven <arjanvandeven@gmail.com>
* Ikey Doherty <michael.i.doherty@intel.com>
*
*/
#define _GNU_SOURCE
#include "nica/util.h"
#include <errno.h>
#include <stddef.h>
#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/socket.h>
#include <sys/types.h>
#include <sys/un.h>
#include <time.h>
#include <unistd.h>
/* 0.75 seconds timeout */
#define TIMEOUT 750000
#define TIMEOUT2 15000
#define TIMEOUT 75000
#define TIMEOUT2 1500
#define TIMEOUT3 500
char *prefix = "src";
@@ -45,71 +47,76 @@ time_t deadtime;
void try_to_get(const char *path, int pid, time_t timestamp)
{
int sockfd;
struct sockaddr_un sun;
int ret;
socklen_t len;
char *command;
fd_set rfds;
struct timeval tv;
struct ucred cred;
int shorttime = 0;
// 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 */
int sockfd;
struct sockaddr_un sun;
int ret;
socklen_t len;
char *command;
fd_set rfds;
struct timeval tv;
struct ucred cred;
int shorttime = 0;
__nc_unused__ size_t wr = -1;
ret = connect(sockfd, (struct sockaddr *)&sun, offsetof(struct sockaddr_un, sun_path) + strlen(":clr-debug-info") + 1);
if (ret < 0) {
printf("Cannot connect %s\n", strerror(errno));
close(sockfd);
return;
}
// printf("Trying to aquire %s\n", path);
len = sizeof(cred);
memset(&cred, 0, sizeof(cred));
ret = getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &len);
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) {
return;
}
if (ret == 0 && cred.pid == pid) {
printf("Recursion\n");
close(sockfd);
}
sun.sun_family = AF_UNIX;
strcpy(sun.sun_path, ":clr-debug-info");
sun.sun_path[0] = 0; /* anonymous unix socket */
command = NULL;
if (asprintf(&command, "%llu:%s:%s", (unsigned long long)timestamp, prefix, path) < 0) {
close(sockfd);
return;
}
write(sockfd, command, strlen(command )+1);
ret = connect(sockfd,
(struct sockaddr *)&sun,
offsetof(struct sockaddr_un, sun_path) + strlen(":clr-debug-info") + 1);
if (ret < 0) {
printf("Cannot connect %s\n", strerror(errno));
close(sockfd);
return;
}
FD_ZERO(&rfds);
FD_SET(sockfd, &rfds);
len = sizeof(cred);
memset(&cred, 0, sizeof(cred));
ret = getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &cred, &len);
/* 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;
}
if (ret == 0 && cred.pid == pid) {
printf("Recursion\n");
close(sockfd);
return;
}
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)
ret = select(sockfd+1, &rfds, NULL, &rfds, &tv);
if (ret == 0 && !shorttime) {
printf("timeout for %s\n", path);
deadtime = time(NULL) + 4;
}
FD_ZERO(&rfds);
FD_SET(sockfd, &rfds);
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);
}
+441 -414
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
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 2 or later of the License.
*
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Authors:
* Arjan van de Ven <arjanvandeven@gmail.com>
* Ikey Doherty <michael.i.doherty@intel.com>
*
*/
#define _GNU_SOURCE
#include <dirent.h>
#include <errno.h>
#include <libgen.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <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/socket.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,
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 part of this symlinks will be resolved server side
as much as possible.
*/
static void unsymlink(char *filename)
{
char *target;
char *target;
__nc_unused__ int r;
target = canonicalize_file_name(filename);
// sleep(1);
// printf("Symlink %s points to %s\n", filename, target);
unlink(filename);
link(target, filename);
target = canonicalize_file_name(filename);
// sleep(1);
// printf("Symlink %s points to %s\n", filename, target);
unlink(filename);
r = link(target, filename);
}
static void wait_for_loadavg(void)
{
FILE *file;
char line[4096];
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);
}
FILE *file;
char line[4096];
__nc_unused__ char *ret = NULL;
while (1) {
double d;
file = fopen("/proc/loadavg", "r");
if (!file) {
return;
}
line[0] = 0;
ret = fgets(line, 4096, file);
fclose(file);
d = strtod(line, NULL);
if (d < 50) {
return;
}
sleep(5);
}
}
int tarcount;
static void do_one_file(char *base1, char *base2, char *path, int isdir)
{
char *fullpath1 = NULL, *fullpath2 = NULL, *dir, *dir2;
struct stat buf1, buf2;
int ret;
char *dir2 = NULL;
autofree(char) * fullpath1, *fullpath2, *dir = NULL;
struct stat buf1, buf2;
int ret;
int sret;
if (asprintf(&fullpath1, "%s%s", base1, path) < 0)
return;
if (asprintf(&fullpath2, "%s%s.tar", base2, path) < 0) {
free(fullpath1);
return;
}
if (asprintf(&fullpath1, "%s%s", base1, path) < 0) {
return;
}
if (asprintf(&fullpath2, "%s%s.tar", base2, path) < 0) {
return;
}
ret = lstat(fullpath1, &buf1);
if (ret)
goto out;
ret = lstat(fullpath1, &buf1);
if (ret) {
return;
}
if (S_ISLNK(buf1.st_mode)) {
// printf("%s is a symlink\n", fullpath1);
ret = stat(fullpath1, &buf2);
if (!ret)
unsymlink(fullpath1);
ret = lstat(fullpath1, &buf1);
}
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);
ret = lstat(fullpath2, &buf2);
if (ret || buf1.st_mtime > buf2.st_mtime) {
char *command = NULL;
unlink(fullpath2);
dir = strdup(fullpath2);
dir = strdup(fullpath2);
dir2 = dirname(dir);
dir2 = dirname(dir);
if (asprintf(&command, "mkdir -p %s", dir2) >= 0) {
// printf("Running -%s-\n", command);
system(command);
free(command);
}
if (dir2) {
(void)nc_mkdir_p(dir2, 00755);
}
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 (chdir(base1) != 0) {
fprintf(stderr, "Failed to chdir: %s\n", strerror(errno));
return;
}
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);
}
}
if (!isdir &&
asprintf(&command,
"tar --no-recursion -C %s -Jcf %s %s &",
base1,
fullpath2,
path) >= 0) {
// printf("Running -%s-\n", command);
printf("Processing %s\n", fullpath2);
tarcount++;
if (tarcount > 50) {
wait_for_loadavg();
tarcount = 0;
}
if ((sret = system(command)) != 0) {
fprintf(stderr, "Failure in command: [%d] %s\n", sret, command);
}
free(command);
}
out:
free(fullpath1);
free(fullpath2);
if (isdir &&
asprintf(&command,
"tar --no-recursion -C %s -Jcf %s `find %s -type d` `find %s "
"-maxdepth 1 -type l` &",
base1,
fullpath2,
path,
path) >= 0) {
// printf("Running -%s-\n", command);
printf("Processing %s\n", fullpath2);
tarcount++;
if (tarcount > 50) {
wait_for_loadavg();
tarcount = 0;
}
if ((sret = system(command)) != 0) {
fprintf(stderr, "Failure in command: [%d] %s\n", sret, command);
}
free(command);
}
}
}
static void recurse_dir(char *base1, char *base2, char *path)
{
DIR *dir;
char *fullpath1, *fullpath2, *newpath;
struct dirent *entry;
DIR *dir;
char *fullpath1 = NULL;
struct dirent *entry;
fullpath1 = NULL;
fullpath2 = NULL;
if (asprintf(&fullpath1, "%s%s", base1, path) < 0) {
return;
}
dir = opendir(fullpath1);
if (asprintf(&fullpath1, "%s%s", base1, path) < 0)
return;
if (!dir) {
return;
}
dir = opendir(fullpath1);
while (1) {
autofree(char) *fullpath2 = NULL;
autofree(char) *newpath = NULL;
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);
entry = readdir(dir);
if (!entry) {
break;
}
if (strcmp(entry->d_name, ".") == 0) {
continue;
}
if (strcmp(entry->d_name, "..") == 0) {
continue;
}
newpath = NULL;
fullpath2 = NULL;
if (asprintf(&fullpath2, "%s/%s", fullpath1, entry->d_name) < 0) {
return;
}
if (asprintf(&newpath, "%s/%s", path, entry->d_name) >= 0) {
struct stat sb;
stat(fullpath2, &sb);
if (entry->d_type == DT_DIR || S_ISDIR(sb.st_mode)) {
do_one_file(base1, base2, newpath, 1);
recurse_dir(base1, base2, newpath);
} else {
do_one_file(base1, base2, newpath, 0);
}
}
}
closedir(dir);
}
int main(int argc, char **argv)
{
if (argc < 0)
(void)argv;
recurse_dir("/var/www/html/debuginfo.raw/usr/lib/debug/", "/var/www/html/debuginfo/lib/", ".");
recurse_dir("/var/www/html/debuginfo.raw/usr/src/debug/", "/var/www/html/debuginfo/src/", ".");
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;
return EXIT_SUCCESS;
}
+408 -181
View File
@@ -9,263 +9,490 @@
* 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/>.
*
* Authors:
* Arjan van de Ven <arjanvandeven@gmail.com>
* Ikey Doherty <michael.i.doherty@intel.com>
*
*/
#define _GNU_SOURCE
#include <errno.h>
#include <grp.h>
#include <linux/capability.h>
#include <malloc.h>
#include <pthread.h>
#include <pwd.h>
#include <signal.h>
#include <stddef.h>
#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 <pthread.h>
#include <sys/prctl.h>
#include <sys/socket.h>
#include <sys/stat.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 <glib.h>
GStaticMutex dupes_mutex = G_STATIC_MUTEX_INIT;
#include "config.h"
#ifdef HAVE_ATOMIC_SUPPORT
#include <stdatomic.h>
#endif
static GHashTable *hash;
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;
static NcHashmap *hash = NULL;
#define MAX_CONNECTIONS 16
static int avoid_dupes(const char *url)
{
int retval = 0;
void *value;
g_static_mutex_lock(&dupes_mutex);
int retval = 0;
void *value;
pthread_mutex_lock(&dupes_mutex);
if (hash == NULL)
hash = g_hash_table_new(g_str_hash, g_str_equal);
if (hash == NULL) {
hash = nc_hashmap_new_full(nc_string_hash, nc_string_compare, free, NULL);
}
if (g_hash_table_lookup_extended(hash, url, NULL, &value)) {
unsigned long tm;
tm = (unsigned long)value;
if (time(NULL) - tm < 600) {
retval = 1;
}
} else {
unsigned long tm;
tm = time(NULL);
void *data = (void *)(unsigned long)tm;
g_hash_table_replace(hash, strdup(url), data);
}
if (nc_hashmap_ensure_get(hash, url, &value)) {
unsigned long tm;
tm = (unsigned long)value;
if (time(NULL) - tm < 600) {
retval = 1;
}
} else {
unsigned long tm;
tm = time(NULL);
void *data = (void *)(unsigned long)tm;
nc_hashmap_put(hash, strdup(url), data);
}
g_static_mutex_unlock(&dupes_mutex);
return retval;
pthread_mutex_unlock(&dupes_mutex);
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)
{
CURLcode code;
CURLcode code;
long ret;
int fd;
char filename[PATH_MAX];
CURL *curl = NULL;
FILE *file;
struct stat statbuf;
long changed;
int fd;
char filename[PATH_MAX];
CURL *curl = NULL;
FILE *file;
struct stat statbuf;
if (avoid_dupes(url))
return 300;
if (avoid_dupes(url)) {
return 300;
}
curl = curl_easy_init();
if (curl == NULL) {
return 301;
}
curl = curl_easy_init();
if (curl == NULL)
return 301;
strcpy(filename, "/tmp/clr-debug-info-XXXXXX");
fd = mkstemp(filename);
if (fd < 0) {
curl_easy_cleanup(curl);
return 500;
}
strcpy(filename, "/tmp/clr-debug-info-XXXXXX");
fd = mkstemp(filename);
if (fd < 0) {
curl_easy_cleanup(curl);
return 500;
}
file = fdopen(fd, "w");
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) {
curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE);
curl_easy_setopt(curl, CURLOPT_TIMEVALUE, timestamp);
}
/* request timestamp of files from server */
curl_easy_setopt(curl, CURLOPT_FILETIME, 1);
code = curl_easy_perform(curl);
if (timestamp) {
curl_easy_setopt(curl, CURLOPT_TIMECONDITION, CURL_TIMECOND_IFMODSINCE);
curl_easy_setopt(curl, CURLOPT_TIMEVALUE, timestamp);
}
/* can't trust the file if we get an error back */
if (code != 0)
unlink(filename);
curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &ret);
fflush(file);
// printf("HTTP return code is %i\n", ret);
code = curl_easy_perform(curl);
if (ret == 200) {
char *command = NULL;
// printf("Filename is %s\n", filename);
/* can't trust the file if we get an error back */
if (code != 0) {
unlink(filename);
}
memset(&statbuf, 0, sizeof(statbuf));
stat(filename, &statbuf);
if (statbuf.st_size > 0 && asprintf(&command, "tar -C /var/cache/debuginfo/%s --no-same-owner -xf %s", prefix, filename) >= 0) {
system(command);
free(command);
}
}
unlink(filename);
curl_easy_cleanup(curl);
fclose(file);
return ret;
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
* timestamp or is newer than that on the server and (b) we haven't
* 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++;
}
if (ret == 200) {
/* get timestamp, if any */
curl_easy_getinfo(curl, CURLINFO_FILETIME, &changed);
if (changed >= 0) {
struct timespec times[2];
times[0].tv_sec = (time_t)changed;
times[0].tv_nsec = 0;
times[1].tv_sec = (time_t)changed;
times[1].tv_nsec = 0;
futimens(fd, times);
}
autofree(char) *command = NULL;
// printf("Filename is %s\n", filename);
memset(&statbuf, 0, sizeof(statbuf));
stat(filename, &statbuf);
if (statbuf.st_size > 0 &&
asprintf(&command,
"tar -C /var/cache/debuginfo/%s --no-same-owner "
"--no-same-permissions -xf %s",
prefix,
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 d;
d = 1.0 * (after.tv_sec - before.tv_sec) + (1.0 * after.tv_usec - before.tv_usec)/1000000.0;
return d;
double d;
d = 1.0 * (after.tv_sec - before.tv_sec) +
(1.0 * after.tv_usec - before.tv_usec) / 1000000.0;
return d;
}
static void *server_thread(void *arg)
{
int fd;
char buf[PATH_MAX+8];
int ret;
char *prefix, *path, *url, *c;
time_t timestamp;
struct timeval before, after;
int fd = -1;
char buf[PATH_MAX + 8];
int ret;
char *prefix, *path, *c = NULL;
autofree(char) *url = NULL;
time_t timestamp;
struct timeval before, after;
__nc_unused__ size_t wr = -1;
fd = (unsigned long)arg;
if (fd < 0)
return NULL;
gettimeofday(&before, NULL);
fd = (unsigned long)arg;
if (fd < 0) {
goto thread_end;
}
gettimeofday(&before, NULL);
memset(buf, 0, sizeof(buf));
ret = read(fd, buf, PATH_MAX+8);
if (ret < 0) {
close(fd);
return NULL;
}
prefix = buf;
c = strchr(buf, ':');
if (!c) {
close(fd);
return NULL;
}
*c = 0;
timestamp = strtoull(buf, NULL, 10);
c++;
prefix = c;
path = strchr(c, ':');
if (!path) {
close(fd);
return NULL;
}
*path = 0;
path++;
memset(buf, 0, sizeof(buf));
ret = read(fd, buf, PATH_MAX + 8);
if (ret < 0) {
goto thread_end;
}
c = strchr(buf, ':');
if (!c) {
goto thread_end;
}
*c = 0;
timestamp = strtoull(buf, NULL, 10);
c++;
prefix = c;
path = strchr(c, ':');
if (!path) {
goto thread_end;
}
*path = 0;
path++;
/* GDB and elfutils both stat /usr/lib/debug directly when looking up
* debuginfo, so avoid the download for "/.tar"; the associated cache
* directories already exist by this point.
*/
if (strlen(path) == 1 && strcmp(path, "/") == 0) {
goto thread_end;
}
if (strstr(path, "..") || strstr(prefix, "..")) {
close(fd);
return NULL;
}
if (strstr(path, "..") || strstr(prefix, "..") || strstr(path, "'") || strstr(path, ";")) {
goto thread_end;
}
if (strcmp(prefix, "lib") !=0 && strcmp(prefix, "src") != 0) {
/* invalid prefix */
close(fd);
return NULL;
}
url = NULL;
if (asprintf(&url, "http://debuginfo.clearlinux.org/debuginfo/%s%s.tar", prefix, path) < 0) {
close(fd);
return NULL;
}
if (strcmp(prefix, "lib") != 0 && strcmp(prefix, "src") != 0) {
/* invalid prefix */
goto thread_end;
}
url = NULL;
if (asprintf(&url, "%s%s%s.tar", urls[urlcounter % 2], prefix, path) < 0) {
goto thread_end;
}
// printf("Getting url %s %i:%06i\n", url, before.tv_sec, before.tv_usec);
ret = curl_get_file(url, prefix, timestamp);
// printf("Getting url %s %i:%06i\n", url, before.tv_sec, before.tv_usec);
ret = curl_get_file(url, prefix, timestamp);
/* tell the other side we're done with the download */
write(fd, "ok", 3);
close(fd);
switch (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);
if (timedelta(before, after) > 0.6)
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);
free(url);
return NULL;
gettimeofday(&after, NULL);
#if 0
if (timedelta(before, after) > 0.6)
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);
thread_end:
if (fd >= 0) {
close(fd);
}
dec_connection_count();
return NULL;
}
int main(int argc, char **argv)
int main(__nc_unused__ int argc, __nc_unused__ char **argv)
{
int sockfd;
struct sockaddr_un sun;
int ret;
int sockfd;
struct sockaddr_un sun;
int ret;
int curl_done = 0;
uid_t dbg_user = 0;
gid_t dbg_group = 0;
struct passwd *passwdentry;
const char *required_paths[] = { "/var/cache/debuginfo/lib", "/var/cache/debuginfo/src" };
if (argc < -1)
(void)argv;
umask(0);
passwdentry = getpwnam("dbginfo");
if (passwdentry) {
dbg_user = passwdentry->pw_uid;
dbg_group = passwdentry->pw_gid;
}
endpwent();
curl_global_init(CURL_GLOBAL_ALL);
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));
}
signal(SIGPIPE,SIG_IGN);
if (geteuid() == 0) {
if (prctl(PR_CAPBSET_DROP, CAP_SYS_ADMIN) != 0) {
fprintf(stderr, "Failed to drop caps: %s\n", strerror(errno));
}
}
if (access("/var/cache/debuginfo/lib/", F_OK))
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");
for (size_t i = 0; i < ARRAY_SIZE(required_paths); i++) {
const char *req_path = required_paths[i];
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;
}
}
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0)
return EXIT_FAILURE;
signal(SIGPIPE, SIG_IGN);
sun.sun_family = AF_UNIX;
strcpy(sun.sun_path, ":clr-debug-info");
sun.sun_path[0] = 0; /* anonymous unix socket */
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sockfd < 0) {
return EXIT_FAILURE;
}
ret = bind(sockfd, (struct sockaddr *)&sun, offsetof(struct sockaddr_un, sun_path) + strlen(":clr-debug-info") + 1);
if (ret < 0) {
printf("Failed to bind:%s \n", strerror(errno));
return EXIT_FAILURE;
}
sun.sun_family = AF_UNIX;
strcpy(sun.sun_path, ":clr-debug-info");
sun.sun_path[0] = 0; /* anonymous unix socket */
if (listen(sockfd, 16) < 0) {
printf("Failed to listen:%s \n", strerror(errno));
return EXIT_FAILURE;
}
ret = bind(sockfd,
(struct sockaddr *)&sun,
offsetof(struct sockaddr_un, sun_path) + strlen(":clr-debug-info") + 1);
if (ret < 0) {
printf("Failed to bind:%s \n", strerror(errno));
return EXIT_FAILURE;
}
if (listen(sockfd, 16) < 0) {
printf("Failed to listen:%s \n", strerror(errno));
return EXIT_FAILURE;
}
while (1) {
int clientsock;
pthread_t thread;
if (setgid(dbg_group)) {
fprintf(stderr, "Unable to drop privileges setgid %s\n", strerror(errno));
return EXIT_FAILURE;
}
if (setgroups(1, &dbg_group)) {
fprintf(stderr, "Unable to drop privileges setgroups %s\n", strerror(errno));
return EXIT_FAILURE;
}
if (setuid(dbg_user)) {
fprintf(stderr, "Unable to drop privileges setuid %s\n", strerror(errno));
return EXIT_FAILURE;
}
clientsock = accept(sockfd, NULL, NULL);
while (1) {
int clientsock;
pthread_t thread;
pthread_create(&thread, NULL, server_thread, (void *)(unsigned long)clientsock);
pthread_detach(thread);
}
close(sockfd);
malloc_trim(0);
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);
}
close(sockfd);
}
+2
View File
@@ -0,0 +1,2 @@
#!/bin/bash
clang-format -i $(find . -name '*.[ch]')