.externalToolBuilders
.settings
*flymake.h.gch
+*.user
- docker pull opensuse:tumbleweed
- docker run -i -d --name test opensuse:tumbleweed bash
- docker exec test zypper ref
-- docker exec test zypper in -y --recommends cmake openssl-devel boost-devel dejagnu doxygen gcc-c++ gettext-devel graphviz libxml2-devel libproxy-devel pkg-config libsolv-devel libsolv-tools ruby rpm-devel libcurl-devel libboost_program_options*-devel libboost_test*-devel libudev-devel xorg-x11-fonts-core xorg-x11-fonts texlive-lm-fonts
+- docker exec test zypper in -y --recommends cmake openssl-devel boost-devel dejagnu doxygen gcc-c++ gettext-devel graphviz libxml2-devel libproxy-devel pkg-config libsolv-devel libsolv-tools ruby rpm-devel libcurl-devel libboost_program_options*-devel libboost_test*-devel libudev-devel xorg-x11-fonts-core xorg-x11-fonts texlive-lm-fonts libgpgme-devel gpgme libboost_thread1_*
+- docker exec test zypper in -y --no-recommends asciidoc
script:
- docker cp ../libzypp/ test:/root
SET( PACKAGE "libzypp" )
# where to look first for cmake modules, before ${CMAKE_ROOT}/Modules/ is checked
SET( CMAKE_MODULE_PATH ${LIBZYPP_SOURCE_DIR}/cmake/modules )
+
cmake_minimum_required(VERSION 2.6)
OPTION (ENABLE_BUILD_DOCS "Build documentation by default?" OFF)
endif ( RPM_SUSPECT_VERSION STREQUAL "5.x" )
ENDIF( NOT RPM_FOUND)
-FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options unit_test_framework)
+FIND_PACKAGE(Boost REQUIRED COMPONENTS program_options unit_test_framework thread)
IF (Boost_FOUND)
MESSAGE( STATUS "boost found: includes in ${Boost_INCLUDE_DIRS}, library in ${Boost_LIBRARY_DIRS}")
INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS})
INCLUDE_DIRECTORIES( ${LibSolv_INCLUDE_DIRS} )
ENDIF()
+FIND_PACKAGE(Gpgme REQUIRED)
+IF ( NOT GPGME_PTHREAD_FOUND )
+ MESSAGE( FATAL_ERROR " gpgme not found" )
+ELSE()
+ INCLUDE_DIRECTORIES( ${GPGME_INCLUDES} )
+ LINK_DIRECTORIES(${GPGME_LIBRARY_DIR})
+ENDIF()
+
FIND_PACKAGE(OpenSSL REQUIRED)
FIND_PACKAGE(Udev)
# See './mkChangelog -h' for help.
#
SET(LIBZYPP_MAJOR "17")
-SET(LIBZYPP_COMPATMINOR "0")
-SET(LIBZYPP_MINOR "1")
-SET(LIBZYPP_PATCH "3")
+SET(LIBZYPP_COMPATMINOR "2")
+SET(LIBZYPP_MINOR "2")
+SET(LIBZYPP_PATCH "0")
#
-# LAST RELEASED: 17.1.3 (0)
+# LAST RELEASED: 17.2.0 (2)
# (The number in parenthesis is LIBZYPP_COMPATMINOR)
#=======
--- /dev/null
+# Taken from gpgmepp project
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# 1. Redistributions of source code must retain the copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#
+# - Try to find the gpgme library
+#
+# Algorithm:
+# - Windows:
+# On Windows, there's three gpgme variants: gpgme{,-glib,-qt}.
+# - The variant used determines the event loop integration possible:
+# - gpgme: no event loop integration possible, only synchronous operations supported
+# - gpgme-glib: glib event loop integration possible, only asynchronous operations supported
+# - gpgme-qt: qt event loop integration possible, only asynchronous operations supported
+# - GPGME_{VANILLA,GLIB,QT}_{FOUND,LIBRARIES} will be set for each of the above
+# - GPGME_INCLUDES is the same for all of the above
+# - GPGME_FOUND is set if any of the above was found
+# - *nix:
+# There's also three variants: gpgme{,-pthread,-pth}.
+# - The variant used determines the multithreaded use possible:
+# - gpgme: no multithreading support available
+# - gpgme-pthread: multithreading available using POSIX threads
+# - gpgme-pth: multithreading available using GNU PTH (cooperative multithreading)
+# - GPGME_{VANILLA,PTH,PTHREAD}_{FOUND,LIBRARIES} will be set for each of the above
+# - GPGME_INCLUDES is the same for all of the above
+# - GPGME_FOUND is set if any of the above was found
+#
+# GPGME_LIBRARY_DIR - the directory where the libraries are located
+
+#
+# THIS IS ALMOST A 1:1 COPY OF FindAssuan.cmake in kdepim.
+# Any changes here likely apply there, too.
+#
+
+include(FeatureSummary)
+
+# do away with crappy condition repetition on else/endfoo
+set( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS_gpgme_saved ${CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS} )
+set( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true )
+
+#if this is built-in, please replace, if it isn't, export into a MacroToBool.cmake of it's own
+macro( macro_bool_to_bool FOUND_VAR )
+ foreach( _current_VAR ${ARGN} )
+ if ( ${FOUND_VAR} )
+ set( ${_current_VAR} TRUE )
+ else()
+ set( ${_current_VAR} FALSE )
+ endif()
+ endforeach()
+endmacro()
+
+#HACK: local copy...
+MACRO(MACRO_BOOL_TO_01 FOUND_VAR )
+ FOREACH (_current_VAR ${ARGN})
+ IF(${FOUND_VAR})
+ SET(${_current_VAR} 1)
+ ELSE(${FOUND_VAR})
+ SET(${_current_VAR} 0)
+ ENDIF(${FOUND_VAR})
+ ENDFOREACH(_current_VAR)
+ENDMACRO(MACRO_BOOL_TO_01)
+
+
+if ( WIN32 )
+
+ # On Windows, we don't have a gpgme-config script, so we need to
+ # look for the stuff ourselves:
+
+ # in cmake, AND and OR have the same precedence, there's no
+ # subexpressions, and expressions are evaluated short-circuit'ed
+ # IOW: CMake if() suxx.
+ # Starting with CMake 2.6.3 you can group if expressions with (), but we
+ # don't require 2.6.3 but 2.6.2, we can't use it. Alex
+ set( _seem_to_have_cached_gpgme false )
+ if ( GPGME_INCLUDES )
+ if ( GPGME_VANILLA_LIBRARIES OR GPGME_QT_LIBRARIES OR GPGME_GLIB_LIBRARIES )
+ set( _seem_to_have_cached_gpgme true )
+ endif()
+ endif()
+
+ if ( _seem_to_have_cached_gpgme )
+
+ macro_bool_to_bool( GPGME_VANILLA_LIBRARIES GPGME_VANILLA_FOUND )
+ macro_bool_to_bool( GPGME_GLIB_LIBRARIES GPGME_GLIB_FOUND )
+ macro_bool_to_bool( GPGME_QT_LIBRARIES GPGME_QT_FOUND )
+ # this would have been preferred:
+ #set( GPGME_*_FOUND macro_bool_to_bool(GPGME_*_LIBRARIES) )
+
+ if ( GPGME_VANILLA_FOUND OR GPGME_GLIB_FOUND OR GPGME_QT_FOUND )
+ set( GPGME_FOUND true )
+ else()
+ set( GPGME_FOUND false )
+ endif()
+
+ else()
+
+ set( GPGME_FOUND false )
+ set( GPGME_VANILLA_FOUND false )
+ set( GPGME_GLIB_FOUND false )
+ set( GPGME_QT_FOUND false )
+
+ find_path( GPGME_INCLUDES gpgme.h
+ ${CMAKE_INCLUDE_PATH}
+ ${CMAKE_INSTALL_PREFIX}/include
+ )
+
+ find_library( _gpgme_vanilla_library NAMES gpgme libgpgme gpgme-11 libgpgme-11
+ PATHS
+ ${CMAKE_LIBRARY_PATH}
+ ${CMAKE_INSTALL_PREFIX}/lib
+ )
+
+ find_library( _gpgme_glib_library NAMES gpgme-glib libgpgme-glib gpgme-glib-11 libgpgme-glib-11
+ PATHS
+ ${CMAKE_LIBRARY_PATH}
+ ${CMAKE_INSTALL_PREFIX}/lib
+ )
+
+ find_library( _gpgme_qt_library NAMES gpgme-qt libgpgme-qt gpgme-qt-11 libgpgme-qt-11
+ PATHS
+ ${CMAKE_LIBRARY_PATH}
+ ${CMAKE_INSTALL_PREFIX}/lib
+ )
+
+ find_library( _gpg_error_library NAMES gpg-error libgpg-error gpg-error-0 libgpg-error-0
+ PATHS
+ ${CMAKE_LIBRARY_PATH}
+ ${CMAKE_INSTALL_PREFIX}/lib
+ )
+
+ set( GPGME_INCLUDES ${GPGME_INCLUDES} )
+
+ if ( _gpgme_vanilla_library AND _gpg_error_library )
+ set( GPGME_VANILLA_LIBRARIES ${_gpgme_vanilla_library} ${_gpg_error_library} )
+ set( GPGME_VANILLA_FOUND true )
+ set( GPGME_FOUND true )
+ endif()
+
+ if ( _gpgme_glib_library AND _gpg_error_library )
+ set( GPGME_GLIB_LIBRARIES ${_gpgme_glib_library} ${_gpg_error_library} )
+ set( GPGME_GLIB_FOUND true )
+ set( GPGME_FOUND true )
+ endif()
+
+ if ( _gpgme_qt_library AND _gpg_error_library )
+ set( GPGME_QT_LIBRARIES ${_gpgme_qt_library} ${_gpg_error_library} )
+ set( GPGME_QT_FOUND true )
+ set( GPGME_FOUND true )
+ endif()
+
+ endif()
+
+ # these are Unix-only:
+ set( GPGME_PTHREAD_FOUND false )
+ set( GPGME_PTH_FOUND false )
+ set( HAVE_GPGME_PTHREAD 0 )
+ set( HAVE_GPGME_PTH 0 )
+
+ macro_bool_to_01( GPGME_FOUND HAVE_GPGME )
+ macro_bool_to_01( GPGME_VANILLA_FOUND HAVE_GPGME_VANILLA )
+ macro_bool_to_01( GPGME_GLIB_FOUND HAVE_GPGME_GLIB )
+ macro_bool_to_01( GPGME_QT_FOUND HAVE_GPGME_QT )
+
+else() # not WIN32
+
+ # On *nix, we have the gpgme-config script which can tell us all we
+ # need to know:
+
+ # see WIN32 case for an explanation of what this does:
+ set( _seem_to_have_cached_gpgme false )
+ if ( GPGME_INCLUDES )
+ if ( GPGME_VANILLA_LIBRARIES OR GPGME_PTHREAD_LIBRARIES OR GPGME_PTH_LIBRARIES )
+ set( _seem_to_have_cached_gpgme true )
+ endif()
+ endif()
+
+ if ( _seem_to_have_cached_gpgme )
+
+ macro_bool_to_bool( GPGME_VANILLA_LIBRARIES GPGME_VANILLA_FOUND )
+ macro_bool_to_bool( GPGME_PTHREAD_LIBRARIES GPGME_PTHREAD_FOUND )
+ macro_bool_to_bool( GPGME_PTH_LIBRARIES GPGME_PTH_FOUND )
+
+ if ( GPGME_VANILLA_FOUND OR GPGME_PTHREAD_FOUND OR GPGME_PTH_FOUND )
+ set( GPGME_FOUND true )
+ else()
+ set( GPGME_FOUND false )
+ endif()
+
+ else()
+
+ set( GPGME_FOUND false )
+ set( GPGME_VANILLA_FOUND false )
+ set( GPGME_PTHREAD_FOUND false )
+ set( GPGME_PTH_FOUND false )
+
+ find_program( _GPGMECONFIG_EXECUTABLE NAMES gpgme-config )
+
+ # if gpgme-config has been found
+ if ( _GPGMECONFIG_EXECUTABLE )
+
+ message( STATUS "Found gpgme-config at ${_GPGMECONFIG_EXECUTABLE}" )
+
+ exec_program( ${_GPGMECONFIG_EXECUTABLE} ARGS --version OUTPUT_VARIABLE GPGME_VERSION )
+
+ set( _GPGME_MIN_VERSION "1.1.7" )
+
+ if ( ${GPGME_VERSION} VERSION_LESS ${_GPGME_MIN_VERSION} )
+
+ message( STATUS "The installed version of gpgme is too old: ${GPGME_VERSION} (required: >= ${_GPGME_MIN_VERSION})" )
+
+ else()
+
+ message( STATUS "Found gpgme v${GPGME_VERSION}, checking for flavours..." )
+
+ exec_program( ${_GPGMECONFIG_EXECUTABLE} ARGS --libs OUTPUT_VARIABLE _gpgme_config_vanilla_libs RETURN_VALUE _ret )
+ if ( _ret )
+ set( _gpgme_config_vanilla_libs )
+ endif()
+
+ exec_program( ${_GPGMECONFIG_EXECUTABLE} ARGS --thread=pthread --libs OUTPUT_VARIABLE _gpgme_config_pthread_libs RETURN_VALUE _ret )
+ if ( _ret )
+ set( _gpgme_config_pthread_libs )
+ endif()
+
+ exec_program( ${_GPGMECONFIG_EXECUTABLE} ARGS --thread=pth --libs OUTPUT_VARIABLE _gpgme_config_pth_libs RETURN_VALUE _ret )
+ if ( _ret )
+ set( _gpgme_config_pth_libs )
+ endif()
+
+ # append -lgpg-error to the list of libraries, if necessary
+ foreach ( _flavour vanilla pthread pth )
+ if ( _gpgme_config_${_flavour}_libs AND NOT _gpgme_config_${_flavour}_libs MATCHES "lgpg-error" )
+ set( _gpgme_config_${_flavour}_libs "${_gpgme_config_${_flavour}_libs} -lgpg-error" )
+ endif()
+ endforeach()
+
+ if ( _gpgme_config_vanilla_libs OR _gpgme_config_pthread_libs OR _gpgme_config_pth_libs )
+
+ exec_program( ${_GPGMECONFIG_EXECUTABLE} ARGS --cflags OUTPUT_VARIABLE _GPGME_CFLAGS )
+
+ if ( _GPGME_CFLAGS )
+ string( REGEX REPLACE "(\r?\n)+$" " " _GPGME_CFLAGS "${_GPGME_CFLAGS}" )
+ string( REGEX REPLACE " *-I" ";" GPGME_INCLUDES "${_GPGME_CFLAGS}" )
+ endif()
+
+ foreach ( _flavour vanilla pthread pth )
+ if ( _gpgme_config_${_flavour}_libs )
+
+ set( _gpgme_library_dirs )
+ set( _gpgme_library_names )
+ string( TOUPPER "${_flavour}" _FLAVOUR )
+
+ string( REGEX REPLACE " +" ";" _gpgme_config_${_flavour}_libs "${_gpgme_config_${_flavour}_libs}" )
+
+ foreach( _flag ${_gpgme_config_${_flavour}_libs} )
+ if ( "${_flag}" MATCHES "^-L" )
+ string( REGEX REPLACE "^-L" "" _dir "${_flag}" )
+ file( TO_CMAKE_PATH "${_dir}" _dir )
+ set( _gpgme_library_dirs ${_gpgme_library_dirs} "${_dir}" )
+ elseif( "${_flag}" MATCHES "^-l" )
+ string( REGEX REPLACE "^-l" "" _name "${_flag}" )
+ set( _gpgme_library_names ${_gpgme_library_names} "${_name}" )
+ endif()
+ endforeach()
+
+ set( GPGME_${_FLAVOUR}_FOUND true )
+
+ foreach( _name ${_gpgme_library_names} )
+ set( _gpgme_${_name}_lib )
+
+ # if -L options were given, look only there
+ if ( _gpgme_library_dirs )
+ find_library( _gpgme_${_name}_lib NAMES ${_name} PATHS ${_gpgme_library_dirs} NO_DEFAULT_PATH )
+ endif()
+
+ # if not found there, look in system directories
+ if ( NOT _gpgme_${_name}_lib )
+ find_library( _gpgme_${_name}_lib NAMES ${_name} )
+ endif()
+
+ # if still not found, then the whole flavour isn't found
+ if ( NOT _gpgme_${_name}_lib )
+ if ( GPGME_${_FLAVOUR}_FOUND )
+ set( GPGME_${_FLAVOUR}_FOUND false )
+ set( _not_found_reason "dependant library ${_name} wasn't found" )
+ endif()
+ endif()
+
+ set( GPGME_${_FLAVOUR}_LIBRARIES ${GPGME_${_FLAVOUR}_LIBRARIES} "${_gpgme_${_name}_lib}" )
+ endforeach()
+
+ #check_c_library_exists_explicit( gpgme gpgme_check_version "${_GPGME_CFLAGS}" "${GPGME_LIBRARIES}" GPGME_FOUND )
+ if ( GPGME_${_FLAVOUR}_FOUND )
+ message( STATUS " Found flavour '${_flavour}', checking whether it's usable...yes" )
+ else()
+ message( STATUS " Found flavour '${_flavour}', checking whether it's usable...no" )
+ message( STATUS " (${_not_found_reason})" )
+ endif()
+ endif()
+
+ endforeach( _flavour )
+
+ # ensure that they are cached
+ # This comment above doesn't make sense, the four following lines seem to do nothing. Alex
+ set( GPGME_INCLUDES ${GPGME_INCLUDES} )
+ set( GPGME_VANILLA_LIBRARIES ${GPGME_VANILLA_LIBRARIES} )
+ set( GPGME_PTHREAD_LIBRARIES ${GPGME_PTHREAD_LIBRARIES} )
+ set( GPGME_PTH_LIBRARIES ${GPGME_PTH_LIBRARIES} )
+
+ if ( GPGME_VANILLA_FOUND OR GPGME_PTHREAD_FOUND OR GPGME_PTH_FOUND )
+ set( GPGME_FOUND true )
+ else()
+ set( GPGME_FOUND false )
+ endif()
+
+ endif()
+
+ endif()
+
+ endif()
+
+ endif()
+
+ # these are Windows-only:
+ set( GPGME_GLIB_FOUND false )
+ set( GPGME_QT_FOUND false )
+ set( HAVE_GPGME_GLIB 0 )
+ set( HAVE_GPGME_QT 0 )
+
+ macro_bool_to_01( GPGME_FOUND HAVE_GPGME )
+ macro_bool_to_01( GPGME_VANILLA_FOUND HAVE_GPGME_VANILLA )
+ macro_bool_to_01( GPGME_PTHREAD_FOUND HAVE_GPGME_PTHREAD )
+ macro_bool_to_01( GPGME_PTH_FOUND HAVE_GPGME_PTH )
+
+endif() # WIN32 | Unix
+
+
+set( _gpgme_flavours "" )
+
+if ( GPGME_VANILLA_FOUND )
+ set( _gpgme_flavours "${_gpgme_flavours} vanilla" )
+endif()
+
+if ( GPGME_GLIB_FOUND )
+ set( _gpgme_flavours "${_gpgme_flavours} Glib" )
+endif()
+
+if ( GPGME_QT_FOUND )
+ set( _gpgme_flavours "${_gpgme_flavours} Qt" )
+endif()
+
+if ( GPGME_PTHREAD_FOUND )
+ set( _gpgme_flavours "${_gpgme_flavours} pthread" )
+endif()
+
+if ( GPGME_PTH_FOUND )
+ set( _gpgme_flavours "${_gpgme_flavours} pth" )
+endif()
+
+# determine the library in one of the found flavours, can be reused e.g. by FindQgpgme.cmake, Alex
+foreach(_currentFlavour vanilla glib qt pth pthread)
+ if(NOT GPGME_LIBRARY_DIR)
+ get_filename_component(GPGME_LIBRARY_DIR "${_gpgme_${_currentFlavour}_lib}" PATH)
+ endif()
+endforeach()
+
+if ( NOT Gpgme_FIND_QUIETLY )
+
+ if ( GPGME_FOUND )
+ message( STATUS "Usable gpgme flavours found: ${_gpgme_flavours}" )
+ else()
+ message( STATUS "No usable gpgme flavours found." )
+ endif()
+
+endif()
+
+if ( Gpgme_FIND_REQUIRED AND NOT GPGME_FOUND )
+ message( FATAL_ERROR "Did not find GPGME" )
+endif()
+
+
+if ( WIN32 )
+ set( _gpgme_homepage "http://www.gpg4win.org" )
+else()
+ set( _gpgme_homepage "http://www.gnupg.org/related_software/gpgme" )
+endif()
+
+set_package_properties(Gpgme PROPERTIES
+ DESCRIPTION "The GnuPG Made Easy (GPGME) library)"
+ URL ${_gpgme_homepage})
+
+set( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS_gpgme_saved )
+
ADD_SUBDIRECTORY( autodoc EXCLUDE_FROM_ALL )
ENDIF ( ENABLE_BUILD_DOCS )
+FIND_PROGRAM(A2X a2x)
+IF (NOT A2X)
+MESSAGE(FATAL_ERROR "Could not find a2x, please install asciidoc")
+ELSE (NOT A2X)
+MESSAGE("a2x found: ${A2X}")
+ENDIF (NOT A2X)
+
+function(ADD_A2X_MANPAGES)
+ set(options)
+ set(oneValueArgs MAN_INST_PATH)
+ set(multiValueArgs MAN_PAGES1 MAN_PAGES2 MAN_PAGES3 MAN_PAGES4 MAN_PAGES5 MAN_PAGES6 MAN_PAGES7 MAN_PAGES8)
+ cmake_parse_arguments(A2X "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} )
+
+ set(ALL_MAN_PAGES)
+
+ FOREACH (MAN_IDX RANGE 1 8)
+ IF (NOT DEFINED A2X_MAN_PAGES${MAN_IDX})
+ CONTINUE()
+ ENDIF()
+
+ FOREACH (curr_PAGE ${A2X_MAN_PAGES${MAN_IDX}})
+ ADD_CUSTOM_COMMAND (
+ OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${curr_PAGE}
+ COMMAND ${A2X} -D ${CMAKE_CURRENT_BINARY_DIR} -f manpage ${CMAKE_CURRENT_SOURCE_DIR}/${curr_PAGE}.txt
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/${curr_PAGE}.txt
+ WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
+ COMMENT "Building manpage ${curr_PAGE}"
+ )
+
+ ADD_CUSTOM_TARGET(
+ ${curr_PAGE}_Target ALL
+ DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${curr_PAGE}
+ )
+
+ INSTALL (
+ FILES ${CMAKE_CURRENT_BINARY_DIR}/${curr_PAGE}
+ DESTINATION "${A2X_MAN_INST_PATH}/man${MAN_IDX}"
+ )
+
+ ENDFOREACH ()
+ ENDFOREACH()
+endfunction(ADD_A2X_MANPAGES)
SET (libzypp_MAN1
zypp-CheckAccessDeleted.1 zypp-NameReqPrv.1)
SET (libzypp_MAN5
locks.5)
-SET (libzypp_MAN
- ${libzypp_MAN1} ${libzypp_MAN5})
-
-ADD_CUSTOM_TARGET( man ALL
- DEPENDS ${libzypp_MAN}
+ADD_A2X_MANPAGES(
+ MAN_INST_PATH ${MANDIR}
+ MAN_PAGES1 ${libzypp_MAN1}
+ MAN_PAGES5 ${libzypp_MAN5}
)
-
-FOREACH (libzypp_MANIDX 1 2 3 4 5 6 7 8)
- INSTALL (FILES
- ${libzypp_MAN${libzypp_MANIDX}}
- DESTINATION ${MANDIR}/man${libzypp_MANIDX}
- )
-ENDFOREACH (libzypp_MANIDX)
-
-#
-# If a2x is installed, auto update manpage from asciidoc manpage.txt:
-#
-FIND_PROGRAM(A2X a2x)
-FOREACH (libzypp_MANTARGET ${libzypp_MAN})
- IF (A2X)
- ADD_CUSTOM_COMMAND (
- OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${libzypp_MANTARGET}
- COMMAND ${A2X} -f manpage ${libzypp_MANTARGET}.txt
- DEPENDS ${libzypp_MANTARGET}.txt
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- )
- ELSE (A2X)
- ADD_CUSTOM_COMMAND (
- OUTPUT ${CMAKE_CURRENT_SOURCE_DIR}/${libzypp_MANTARGET}
- DEPENDS ${libzypp_MANTARGET}.txt
- WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
- COMMENT "Forgott to fix manpage after changing ascidoc? Install a2x for automated creation or 'touch ${libzypp_MANTARGET}'"
- )
- ENDIF (A2X)
-ENDFOREACH (libzypp_MANTARGET)
-
-
+++ /dev/null
-'\" t
-.\" Title: locks
-.\" Author: [see the "AUTHORS" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 06/12/2015
-.\" Manual: LIBZYPP
-.\" Source: SUSE Linux
-.\" Language: English
-.\"
-.TH "LOCKS" "5" "06/12/2015" "SUSE Linux" "LIBZYPP"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-locks \- libzypp locking file
-.SH "DESCRIPTION"
-.sp
-The file \fI/etc/zypp/locks\fR is read by libzypp at start\-up if \fIzypp\&.conf\fR allows it\&. The entries are used for initial locking of packages\&. Locking a package means not allowing to install or uninstall it\&.
-.sp
-Valid entries are of the form:
-.PP
-\fIattribute\fR\fB:\fR \fIvalue\fR
-.RS 4
-Where attributes and their values are described below\&.
-.RE
-.sp
-Locks are separated by an empty lines\&.
-.SH "ATTRIBUTES"
-.sp
-All attributes are lower\-case\&.
-.PP
-\fBrepo\fR
-.RS 4
-specifies repository restriction\&. Only alias is accepted\&.
-
-By default all repositories match\&.
-.RE
-.PP
-\fBtype\fR
-.RS 4
-resolvable type restriction\&. The values can be
-\fBpackage\fR,
-\fBpatch\fR,
-\fBpattern\fR,
-\fBproduct\fR
-and
-\fBsrcpackage\fR\&.
-
-By default all types match\&.
-.RE
-.PP
-\fBcase_sensitive\fR
-.RS 4
-if strings are matched case sensitive\&. The values are
-\fBtrue\fR,
-\fBfalse\fR,
-\fBon\fR,
-\fBoff\fR\&.
-
-The default is case insensitive\&.
-.RE
-.PP
-\fBinstall_status\fR
-.RS 4
-status of object\&. Possible states are
-\fBinstalled\fR,
-\fBnot\-installed\fR
-and
-\fBall\fR\&. If more install statuses are specified then the last one is used\&. The values are
-\fBinstalled\fR
-for all packages which are installed,
-\fBnon\-installed\fR
-for packages which can be installed or reinstalled and
-\fBall\fR
-for both\&.
-
-The default is
-\fBall\fR\&.
-.RE
-.PP
-\fBmatch_type\fR
-.RS 4
-type of string matching in values\&. Does not affect
-\fBtype\fR
-and
-\fBrepo\fR
-which must be specified exactly\&. The values are
-\fBexact\fR,
-\fBsubstring\fR,
-\fBregex\fR
-for regular expressions,
-\fBglob\fR
-for matching as on the command line, and
-\fBword\fR\&.
-
-The default is
-\fBsubstring\fR\&.
-.RE
-.PP
-\fBquery_string\fR
-.RS 4
-String to be matched in multiple attributes\&. Should be restricted by another attribute with empty value (it is recommended, because without restriction expect some performance problems)\&.
-.RE
-.PP
-\fBversion\fR
-.RS 4
-Restrict the lock only to some versions\&. It contains two parts: an optional operator and the version\&.
-
-The operator is
-\fB==\fR,
-\fB!=\fR,
-\fB<\fR,
-\fB>\fR,
-\fB⇐\fR,
-\fB>=\fR\&. If operator is not specified then
-\fB==\fR
-is used\&.
-
-The version has the format [\fIepoch\fR\fB:\fR]\fIversion\fR[\fB\-\fR\fIrelease\fR]\&.
-
-Example:
-\fBversion: < 0:0\&.11\&.4\-2\fR
-.RE
-.PP
-\fBsolvable_name\fR
-.RS 4
-name of object (e\&.g\&. zypper)
-.RE
-.PP
-\fBsolvable_summary\fR
-.RS 4
-summary of object
-.RE
-.PP
-\fBsolvable_arch\fR
-.RS 4
-architecture of object (e\&.g\&. x86_64, i586)
-.RE
-.PP
-\fBsolvable_description\fR
-.RS 4
-description of object
-.RE
-.PP
-\fBsolvable_eula\fR
-.RS 4
-license text of objects which request accepting license by user
-.RE
-.PP
-\fBsolvable_license\fR
-.RS 4
-license of package (only for package) (e\&.g\&. GPL2)
-.RE
-.PP
-\fBsolvable_keywords\fR
-.RS 4
-keywords which specify package (only for package)
-.RE
-.PP
-\fBsolvable_authors\fR
-.RS 4
-authors of package (only for package)
-.RE
-.PP
-\fBsolvable_group\fR
-.RS 4
-package group (only for package) (e\&.g\&. Development/Tools/Version Control )
-.RE
-.PP
-\fBupdate_reference_type\fR
-.RS 4
-reference for update (e\&.g\&. bugzilla,cve) (only for patches)
-.RE
-.SH "EXAMPLES"
-.PP
-\fBExact Package\fR
-.RS 4
-This is the way YaST UI does it\&. Lock k3b (e\&.g\&. you don\(cqt want to update it)\&.
-.RE
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\-\-\-\-\-locks\-\-\-\-\-
-type: package
-solvable_name: k3b
-match_type: exact
-case_sensitive: on
-.fi
-.if n \{\
-.RE
-.\}
-.PP
-\fBPackage Wildcard\fR
-.RS 4
-This is the way "zypper addlock cross\-*\-gcc\-icecream\-backend" does it\&.
-.RE
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\-\-\-\-\-locks\-\-\-\-\-
-type: package
-solvable_name: cross\-*\-gcc\-icecream\-backend
-match_type: glob
-case_sensitive: on
-.fi
-.if n \{\
-.RE
-.\}
-.PP
-\fBVersioned Lock\fR
-.RS 4
-Do not install new GCC\&. This format is used when converting from the openSUSE\-10\&.3 lock format\&.
-.RE
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\-\-\-\-\-locks\-\-\-\-\-
-solvable_name: gcc
-match_type: glob
-version: > 4\&.2
-.fi
-.if n \{\
-.RE
-.\}
-.PP
-\fBAnything named KDE\fR
-.RS 4
-Locks everything which contains kde in the name\&.
-.RE
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\-\-\-\-\-locks\-\-\-\-\-
-solvable_name: kde
-.fi
-.if n \{\
-.RE
-.\}
-.PP
-\fBAnything mentioning KDE\fR
-.RS 4
-Locks everything which contains kde in the name, summary, or description\&.
-.RE
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-\-\-\-\-\-locks\-\-\-\-\-
-query_string: kde
-solvable_name:
-solvable_summary:
-solvable_description:
-.fi
-.if n \{\
-.RE
-.\}
-.SH "HOMEPAGE"
-.sp
-This manual page only covers the most important attributes\&. The complete list is available at http://en\&.opensuse\&.org/Libzypp/Locksfile
-.SH "AUTHORS"
-.sp
-Josef Reidinger <jreidinger@suse\&.cz> Manual page contributions by Martin Vidner <mvidner@suse\&.cz>\&.
-.SH "SEE ALSO"
-.sp
-zypper(8)
+++ /dev/null
-'\" t
-.\" Title: zypp-checkaccessdeleted
-.\" Author: [see the "AUTHORS" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 06/12/2015
-.\" Manual: LIBZYPP
-.\" Source: SUSE Linux
-.\" Language: English
-.\"
-.TH "ZYPP\-CHECKACCESSDEL" "1" "06/12/2015" "SUSE Linux" "LIBZYPP"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-zypp-CheckAccessDeleted \- List processes which access deleted files
-.SH "SYNOPSIS"
-.sp
-\fBzypp\-CheckAccessDeleted\fR [\fIOPTION\fR]\&...
-.SH "DESCRIPTION"
-.sp
-List running processes which access deleted files\&. This may help to identify services and processes which need to be restarted after an update, e\&.g\&. if they still refer to meanwhile deleted libraries\&. The output is similar to \(oq\fBzypper ps\fR\(cq but does not sort out processes accessing normal files only\&.
-.SH "OPTIONS"
-.PP
-\fB\-\-help\fR
-.RS 4
-display help and exit
-.RE
-.SH "AUTHORS"
-.sp
-Michael Andres <ma@suse\&.de>
-.SH "SEE ALSO"
-.sp
-zypper(8)
-------
*--help*::
display help and exit
+*--zypper*::
+ use less verbose zypper mode to list processes
+*--debugFile* 'filename'::
+ Reads process and opened files information from a file that was created by zypper previously
AUTHORS
+++ /dev/null
-'\" t
-.\" Title: zypp-namereqprv
-.\" Author: [see the "AUTHORS" section]
-.\" Generator: DocBook XSL Stylesheets v1.78.1 <http://docbook.sf.net/>
-.\" Date: 06/12/2015
-.\" Manual: LIBZYPP
-.\" Source: SUSE Linux
-.\" Language: English
-.\"
-.TH "ZYPP\-NAMEREQPRV" "1" "06/12/2015" "SUSE Linux" "LIBZYPP"
-.\" -----------------------------------------------------------------
-.\" * Define some portability stuff
-.\" -----------------------------------------------------------------
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.\" http://bugs.debian.org/507673
-.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html
-.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-.ie \n(.g .ds Aq \(aq
-.el .ds Aq '
-.\" -----------------------------------------------------------------
-.\" * set default formatting
-.\" -----------------------------------------------------------------
-.\" disable hyphenation
-.nh
-.\" disable justification (adjust text to left margin only)
-.ad l
-.\" -----------------------------------------------------------------
-.\" * MAIN CONTENT STARTS HERE *
-.\" -----------------------------------------------------------------
-.SH "NAME"
-zypp-NameReqPrv \- Investigate packages and dependencies in solver test\-cases
-.SH "SYNOPSIS"
-.sp
-\fBzypp\-NameReqPrv\fR [\fB\-\-root\fR \fIDIR\fR] [[\fIOPTIONS\fR] \fINAME\fR\&...]\&...
-.SH "DESCRIPTION"
-.sp
-Load all enabled repositories (without refresh) and search for occurrences of regular expression \fINAME\fR in package names or dependencies\&. In case \fIDIR\fR denotes a directory containing a solver test\-case, repositories and settings provided by the test\-case are loaded instead\&.
-.sp
-A solver test\-case is an abstract of repositories, packages, hardware and dependency resolution related settings which can be created by using zyppers \fB\-\-debug\-solver\fR option\&. Attached to a bug report the test\-case helps investigating the reported behavior\&. Options and output of this command are tailored to this use\-case and may change as needed\&.
-.sp
-Reported matches show the packages \fIinternal id\fR, \fIname\fR, \fIversion\fR and \fIarchitecture\fR, \fIpriority\fR and name of the providing \fIrepository\fR, \fIvendor\fR, \fIbuildtime\fR and the locations matching \fINAME\fR\&.
-.sp
-.if n \{\
-.RS 4
-.\}
-.nf
-2431 zypper\-1\&.9\&.16\-22\&.2\&.x86_64 (99)@System openSUSE 1400499579
- nam: zypper
-40947 zypper\-1\&.9\&.3\-1\&.1\&.x86_64 (99)repo\-oss (13\&.1) openSUSE 1383049437
- nam: zypper
-56140 zypper\-1\&.9\&.16\-22\&.2\&.x86_64 (99)repo\-oss\-update (13\&.1) openSUSE 1400499579
- nam: zypper
-.fi
-.if n \{\
-.RE
-.\}
-.SH "OPTIONS"
-.PP
-\fB\-\-root\fR \fIDIR\fR
-.RS 4
-Load repos from the system located below
-\fIDIR\fR\&. If
-\fIDIR\fR
-denotes a solver test\-case, the test\-case is loaded\&.
-.RE
-.PP
-\fB\-\-installed\fR
-.RS 4
-Process installed packages only\&.
-.RE
-.PP
-\fB\-i\fR/\fB\-I\fR
-.RS 4
-Turn on/off case insensitive search (default on)
-.RE
-.PP
-\fB\-n\fR/\fB\-N\fR
-.RS 4
-Turn on/off looking for names (default on)
-.RE
-.PP
-\fB\-p\fR/\fB\-P\fR
-.RS 4
-Turn on/off looking for provides (default off)
-.RE
-.PP
-\fB\-r\fR/\fB\-R\fR
-.RS 4
-Turn on/off looking for requires (default off)
-.RE
-.PP
-\fB\-c\fR/\fB\-C\fR
-.RS 4
-Turn on/off looking for conflicts (default off)
-.RE
-.PP
-\fB\-o\fR/\fB\-O\fR
-.RS 4
-Turn on/off looking for obsoletes (default off)
-.RE
-.PP
-\fB\-m\fR/\fB\-M\fR
-.RS 4
-Turn on/off looking for recommends (default off)
-.RE
-.PP
-\fB\-s\fR/\fB\-S\fR
-.RS 4
-Turn on/off looking for supplements (default off)
-.RE
-.PP
-\fB\-a\fR
-.RS 4
-Short for
-\fB\-n \-p \-r\fR
-.RE
-.PP
-\fB\-A\fR
-.RS 4
-Short for
-\fB\-n \-P \-R\fR
-.RE
-.PP
-\fB\-D\fR \fIPKG\fR
-.RS 4
-Dump dependencies of package
-\fIPKG\fR
-(exact name)\&.
-.RE
-.SH "AUTHORS"
-.sp
-Michael Andres <ma@suse\&.de>
-.SH "SEE ALSO"
-.sp
-zypper(8)
BuildRequires: pkg-config
%endif
-BuildRequires: libsolv-devel >= 0.6.23
+BuildRequires: libsolv-devel >= 0.6.27
%if 0%{?suse_version} >= 1100
BuildRequires: libsolv-tools
%requires_eq libsolv-tools
%endif
%if 0%{?suse_version}
-BuildRequires: gpg2
-Requires: gpg2
+BuildRequires: libgpgme-devel
%else
-BuildRequires: gnupg2
-Requires: gnupg2
+BuildRequires: gpgme-devel
%endif
%define min_curl_version 7.19.4
Requires: libcurl >= %{min_curl_version}
%endif
+# required for documentation
+BuildRequires: asciidoc
+
%description
Package, Patch, Pattern, and Product Management
-------------------------------------------------------------------
+Thu Mar 1 17:46:39 CET 2018 - bzeller@suse.de
+
+- Add /var/lib/gdm to CheckAccessDeleted blacklist (bsc#1079991)
+- Use gpgme instead of calling gpg2 binary directly
+- Fix leak in Digest.cc (bsc#1075978)
+- version 17.2.0 (2)
+
+-------------------------------------------------------------------
Tue Feb 20 18:03:24 CET 2018 - ma@suse.de
- RpmDb::checkPackage: fix parsing localized rpm output (bsc#1076415)
"Project-Id-Version: opensuse-i 18n\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-12-01 07:26+0100\n"
-"PO-Revision-Date: 2017-09-14 21:15+0000\n"
-"Last-Translator: hayyan rostami <hayyan71@yahoo.com>\n"
-"Language-Team: Persian <https://l10n.opensuse.org/projects/libzypp/master/fa/"
-">\n"
+"PO-Revision-Date: 2018-02-28 13:09+0000\n"
+"Last-Translator: Mohammad Rezaei Seresht <m_rezaei_seresht@hotmail.com>\n"
+"Language-Team: Persian "
+"<https://l10n.opensuse.org/projects/libzypp/master/fa/>\n"
"Language: fa\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=n > 1;\n"
-"X-Generator: Weblate 2.13.1\n"
+"X-Generator: Weblate 2.18\n"
#: zypp/target/hal/HalException.h:46 zypp/target/hal/HalException.h:55
#: zypp/target/hal/HalException.h:64
msgstr "برای وارد کردن کلید ناموجود %s در دسته کلید %s تلاش شد"
#: zypp/KeyRing.cc:583
-#, fuzzy
msgid "Failed to import key."
-msgstr "ناموفق در وارد کردن کلید عمومی از پرونده ی %1%"
+msgstr "ناموفق در وارد کردن کلید."
#: zypp/KeyRing.cc:606
msgid "Failed to delete key."
#: zypp/PublicKey.cc:65
#, boost-format
msgid "expired: %1%"
-msgstr ""
+msgstr "منقضی شده: %1%"
#. translators: an annotation to a gpg keys expiry date: "expires: 2111-04-12"
#: zypp/PublicKey.cc:70
#, boost-format
msgid "expires: %1%"
-msgstr ""
+msgstr "تاریخ انقضا: %1%"
#. translators: an annotation to a gpg keys expiry date
#: zypp/PublicKey.cc:79
#: zypp/target/rpm/RpmDb.cc:1596
msgid "Package is not signed!"
-msgstr ""
+msgstr "بسته مورد تایید نیست!"
#. Translator: %s = name of an rpm package. A list of diffs follows
#. this message.
#. translators: possible rpm package signature check result [brief]
#: zypp/target/rpm/RpmDb.cc:2424
msgid "File is unsigned"
-msgstr ""
+msgstr "فایل تایید نشده"
#: zypp/thread/Mutex.cc:33
msgid "Can't initialize mutex attributes"
virtual void trustedKeyAdded( const PublicKey & key_r )
{ ++_cbcnt; }
+ virtual void trustedKeyRemoved( const PublicKey & key_r )
+ { --_cbcnt; }
+
unsigned _cbcnt = 0;
} receiver;
BOOST_CHECK_EQUAL( receiver._cbcnt, keyring.trustedPublicKeys().size() );
}
+BOOST_AUTO_TEST_CASE(keyring_delete)
+{
+ PublicKey key( Pathname(DATADIR) + "public.asc" );
+ /** scenario #3
+ * import and delete untrusted key
+ */
+ {
+ // base sandbox for playing
+ TmpDir tmp_dir;
+ KeyRing keyring( tmp_dir.path() );
+
+ BOOST_CHECK_EQUAL( keyring.publicKeys().size(), (unsigned) 0 );
+ BOOST_CHECK_EQUAL( keyring.trustedPublicKeys().size(), (unsigned) 0 );
+
+ keyring.importKey( key, false );
+
+ BOOST_CHECK_EQUAL( keyring.publicKeys().size(), (unsigned) 1 );
+ BOOST_CHECK_EQUAL( keyring.trustedPublicKeys().size(), (unsigned) 0 );
+
+ keyring.deleteKey( key.id(), false);
+
+ BOOST_CHECK_EQUAL( keyring.publicKeys().size(), (unsigned) 0 );
+ BOOST_CHECK_EQUAL( keyring.trustedPublicKeys().size(), (unsigned) 0 );
+ }
+
+ /** scenario #3.1
+ * import and delete trusted key
+ */
+ {
+ // base sandbox for playing
+ TmpDir tmp_dir;
+ KeyRing keyring( tmp_dir.path() );
+
+ BOOST_CHECK_EQUAL( keyring.publicKeys().size(), (unsigned) 0 );
+ BOOST_CHECK_EQUAL( keyring.trustedPublicKeys().size(), (unsigned) 0 );
+
+ keyring.importKey( key, true );
+
+ BOOST_CHECK_EQUAL( keyring.publicKeys().size(), (unsigned) 0 );
+ BOOST_CHECK_EQUAL( keyring.trustedPublicKeys().size(), (unsigned) 1 );
+
+ //try to delete from untrusted keyring
+ keyring.deleteKey( key.id(), false);
+
+ BOOST_CHECK_EQUAL( keyring.publicKeys().size(), (unsigned) 0 );
+ BOOST_CHECK_EQUAL( keyring.trustedPublicKeys().size(), (unsigned) 1 );
+
+ keyring.deleteKey( key.id(), true);
+
+ BOOST_CHECK_EQUAL( keyring.publicKeys().size(), (unsigned) 0 );
+ BOOST_CHECK_EQUAL( keyring.trustedPublicKeys().size(), (unsigned) 0 );
+ }
+}
+
TableCol files;
};
+void usage ( const std::string &appname )
+{
+ std::cout << "Usage: " << appname << " [--help] [--debugFile <file>] [--zypper]" << std::endl;
+ std::cout << "List information about all running processe" << std::endl;
+ std::cout << "which access deleted executables or libraries." << std::endl;
+ std::cout << std::endl;
+ std::cout << "GLOBALOPTS:" << std::endl;
+ std::cout << " --debugFile <file> Use information from <file> instead" << std::endl;
+ std::cout << " of inspecting the host system." << std::endl;
+ std::cout << " --zypper Disable verbose checking like zypper does." << std::endl;
+ std::cout << std::endl;
+ std::cout << "TABLEHEADERS:" << std::endl;
+ std::cout << " PID " << "process ID" << std::endl;
+ std::cout << " PPID " << "parent process ID" << std::endl;
+ std::cout << " UID " << "process user ID" << std::endl;
+ std::cout << " LOGIN " << "process login name" << std::endl;
+ std::cout << " COMMAND " << "process command name" << std::endl;
+ std::cout << " SERVICE " << "/etc/init.d/ script that might be used to restart the command (guessed)" << std::endl;
+ std::cout << " FILES " << "list of deleted executables or libraries accessed" << std::endl;
+}
+
int main( int argc, char * argv[] )
{
- if ( argc >= 2 )
- {
- std::string progname( zypp::Pathname::basename( argv[0] ) );
- if ( strcmp( argv[1], "--help" ) == 0 )
+
+ std::string progname( zypp::Pathname::basename( argv[0] ) );
+ std::string debugInputFile;
+ bool verbose = true;
+ argv++;
+ argc--;
+
+ while( argc > 0 ) {
+ if ( strcmp( argv[0], "--help" ) == 0 )
{
- std::cout << "Usage: " << progname << " [--help]" << std::endl;
- std::cout << "List information about all running processe" << std::endl;
- std::cout << "which access deleted executables or libraries." << std::endl;
- std::cout << " PID " << "process ID" << std::endl;
- std::cout << " PPID " << "parent process ID" << std::endl;
- std::cout << " UID " << "process user ID" << std::endl;
- std::cout << " LOGIN " << "process login name" << std::endl;
- std::cout << " COMMAND " << "process command name" << std::endl;
- std::cout << " SERVICE " << "/etc/init.d/ script that might be used to restart the command (guessed)" << std::endl;
- std::cout << " FILES " << "list of deleted executables or libraries accessed" << std::endl;
+ usage( progname );
return 0;
+ } else if ( strcmp( argv[0], "--debugFile" ) == 0 ) {
+ if ( argc < 2 ) {
+ std::cerr << progname << ": debugFile requires a argument" << std::endl;
+ return 1;
+ }
+
+ argv++;
+ argc--;
+ debugInputFile = argv[0];
+
+ } else if ( strcmp( argv[0], "--zypper" ) == 0 ) {
+ verbose = false;
+ } else {
+ std::cerr << progname << ": unexpected argument '" << argv[0] << "'" << std::endl;
+ std::cerr << "Try `" << progname << " --help' for more information." << std::endl;
+ return 1;
}
- std::cerr << progname << ": unexpected argument '" << argv[1] << "'" << std::endl;
- std::cerr << "Try `" << progname << " --help' for more information." << std::endl;
- return 1;
+
+ argv++;
+ argc--;
}
zypp::CheckAccessDeleted checker(false); // wait for explicit call to check()
try {
- checker.check( /*verbose*/true );
+ if ( debugInputFile.empty() )
+ checker.check( verbose );
+ else
+ checker.check( debugInputFile, verbose );
}
catch( const zypp::Exception & err )
{
HistoryLogData.cc
IdString.cc
InstanceId.cc
+ KeyManager.cc
KeyRing.cc
Locks.cc
MediaSetAccess.cc
IdStringType.h
InstanceId.h
KeyContext.h
+ KeyManager.h
KeyRing.h
KVMap.h
LanguageCode.h
TARGET_LINK_LIBRARIES(zypp ${LibSolv_LIBRARIES} )
TARGET_LINK_LIBRARIES(zypp ${OPENSSL_LIBRARIES} )
TARGET_LINK_LIBRARIES(zypp ${CRYPTO_LIBRARIES} )
-TARGET_LINK_LIBRARIES(zypp ${SIGNALS_LIBRARY} )
+TARGET_LINK_LIBRARIES(zypp ${SIGNALS_LIBRARY})
+TARGET_LINK_LIBRARIES(zypp ${Boost_THREAD_LIBRARY})
+TARGET_LINK_LIBRARIES(zypp ${GPGME_PTHREAD_LIBRARIES})
+
IF ( UDEV_FOUND )
TARGET_LINK_LIBRARIES(zypp ${UDEV_LIBRARY} )
#endif
#include "zypp/Digest.h"
+#include "zypp/base/PtrTypes.h"
namespace zypp {
// private data
class Digest::P
{
- P(const P& p);
- const P& operator=(const P& p);
+ P(const P& p);
+ const P& operator=(const P& p);
+
public:
- P();
- ~P();
+ typedef zypp::shared_ptr<EVP_MD_CTX> EvpDataPtr;
+ P();
+ ~P();
- EVP_MD_CTX *mdctx;
+ EvpDataPtr mdctx;
- const EVP_MD *md;
- unsigned char md_value[EVP_MAX_MD_SIZE];
- unsigned md_len;
+ const EVP_MD *md;
+ unsigned char md_value[EVP_MAX_MD_SIZE];
+ unsigned md_len;
- bool initialized : 1;
- bool finalized : 1;
- static bool openssl_digests_added;
+ bool finalized : 1;
+ static bool openssl_digests_added;
- std::string name;
+ std::string name;
- inline bool maybeInit();
- inline void cleanup();
+ inline bool maybeInit();
+ inline void cleanup();
};
Digest::P::P() :
md(NULL),
- initialized(false),
finalized(false)
{
}
{
if(!openssl_digests_added)
{
- OPENSSL_config(NULL);
- ENGINE_load_builtin_engines();
- ENGINE_register_all_complete();
- OpenSSL_add_all_digests();
- openssl_digests_added = true;
+ OPENSSL_config(NULL);
+ ENGINE_load_builtin_engines();
+ ENGINE_register_all_complete();
+ OpenSSL_add_all_digests();
+ openssl_digests_added = true;
}
- if(!initialized)
+ if(!mdctx)
{
- md = EVP_get_digestbyname(name.c_str());
- if(!md)
- return false;
+ md = EVP_get_digestbyname(name.c_str());
+ if(!md)
+ return false;
#if OPENSSL_VERSION_NUMBER < 0x10100000L
- mdctx = (EVP_MD_CTX*) malloc(sizeof(EVP_MD_CTX));
- EVP_MD_CTX_init(mdctx);
+ EvpDataPtr tmp_mdctx(EVP_MD_CTX_create(), EVP_MD_CTX_destroy);
#else
- mdctx = EVP_MD_CTX_new();
+ EvpDataPtr tmp_mdctx(EVP_MD_CTX_new(), EVP_MD_CTX_free);
#endif
- if(!EVP_DigestInit_ex(mdctx, md, NULL))
- return false;
+ if (!tmp_mdctx)
+ return false;
+
+ if (!EVP_DigestInit_ex(tmp_mdctx.get(), md, NULL)) {
+ return false;
+ }
- md_len = 0;
- ::memset(md_value, 0, sizeof(md_value));
- initialized = true;
+ md_len = 0;
+ ::memset(md_value, 0, sizeof(md_value));
+
+ mdctx.swap(tmp_mdctx);
}
return true;
}
void Digest::P::cleanup()
{
- if(initialized)
- {
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
- EVP_MD_CTX_cleanup(mdctx);
-#else
- EVP_MD_CTX_free(mdctx);
-#endif
- initialized = false;
- finalized = false;
- }
+ mdctx.reset();
+ finalized = false;
}
Digest::Digest() : _dp(new P())
{
if(name.empty()) return false;
- if(_dp->initialized)
+ if(_dp->mdctx)
_dp->cleanup();
_dp->name = name;
bool Digest::reset()
{
- if (!_dp->initialized)
- return false;
+ if (!_dp->mdctx)
+ return false;
if(!_dp->finalized)
- {
- (void)EVP_DigestFinal_ex(_dp->mdctx, _dp->md_value, &_dp->md_len);
- _dp->finalized = true;
- }
- if(!EVP_DigestInit_ex(_dp->mdctx, _dp->md, NULL))
- return false;
+ {
+ (void)EVP_DigestFinal_ex(_dp->mdctx.get(), _dp->md_value, &_dp->md_len);
+ _dp->finalized = true;
+ }
+ if(!EVP_DigestInit_ex(_dp->mdctx.get(), _dp->md, NULL))
+ return false;
_dp->finalized = false;
return true;
}
if(!_dp->finalized)
{
- if(!EVP_DigestFinal_ex(_dp->mdctx, _dp->md_value, &_dp->md_len))
+ if(!EVP_DigestFinal_ex(_dp->mdctx.get(), _dp->md_value, &_dp->md_len))
return std::string();
_dp->finalized = true;
if(!_dp->finalized)
{
- if(!EVP_DigestFinal_ex(_dp->mdctx, _dp->md_value, &_dp->md_len))
+ if(!EVP_DigestFinal_ex(_dp->mdctx.get(), _dp->md_value, &_dp->md_len))
return r;
_dp->finalized = true;
}
return false;
}
- if(!EVP_DigestUpdate(_dp->mdctx, reinterpret_cast<const unsigned char*>(bytes), len))
+ if(!EVP_DigestUpdate(_dp->mdctx.get(), reinterpret_cast<const unsigned char*>(bytes), len))
return false;
return true;
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ V /| _/ _/ |
+| / /__ | | | | | | |
+| /_____||_| |_| |_| |
+| |
+\---------------------------------------------------------------------*/
+#include "zypp/KeyManager.h"
+#include "zypp/PublicKey.h"
+#include "zypp/PathInfo.h"
+#include "zypp/base/Logger.h"
+#include "zypp/TmpPath.h"
+#include "zypp/base/String.h"
+
+#include <boost/thread/once.hpp>
+#include <boost/interprocess/smart_ptr/scoped_ptr.hpp>
+#include <gpgme.h>
+
+#include <stdio.h>
+
+#undef ZYPP_BASE_LOGGER_LOGGROUP
+#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::gpg"
+
+// @TODO [threading]
+// make sure to call the init code of gpgme only once
+// this might need to be moved to a different location when
+// threads are introduced into libzypp
+boost::once_flag gpgme_init_once = BOOST_ONCE_INIT;
+using std::endl;
+
+//using boost::interprocess pointer because it allows a custom deleter
+typedef boost::interprocess::scoped_ptr<gpgme_data, boost::function<void (gpgme_data_t)>> GpgmeDataPtr;
+typedef boost::interprocess::scoped_ptr<_gpgme_key, boost::function<void (gpgme_key_t)>> GpgmeKeyPtr;
+typedef boost::interprocess::scoped_ptr<FILE, boost::function<int (FILE *)>> FILEPtr;
+
+struct GpgmeErr
+{
+ GpgmeErr( gpgme_error_t err_r = GPG_ERR_NO_ERROR )
+ : _err( err_r )
+ {}
+ operator gpgme_error_t() const { return _err; }
+private:
+ gpgme_error_t _err;
+};
+std::ostream & operator<<( std::ostream & str, const GpgmeErr & obj )
+{ return str << "<" << gpgme_strsource(obj) << "> " << gpgme_strerror(obj); }
+
+static void initGpgme ()
+{
+ gpgme_check_version(NULL);
+
+}
+
+namespace zypp
+{
+
+class KeyManagerCtx::Impl
+{
+public:
+ Impl();
+ ~Impl();
+
+ std::list<std::string> verifyAndReadSignaturesFprs(const Pathname & file, const Pathname & signature, bool &verifed);
+
+ gpgme_ctx_t _ctx;
+};
+
+KeyManagerCtx::Impl::Impl()
+{ }
+
+
+KeyManagerCtx::KeyManagerCtx()
+ : _pimpl( new Impl )
+{
+
+}
+
+/*
+ * \brief KeyManagerCtx::Impl::verifyAndReadSignaturesFprs
+ * Tries to verify the \a file using \a signature , will return all
+ * signatures and sets \a verified to true if all signatures are good
+ * \internal
+ */
+std::list<std::string> KeyManagerCtx::Impl::verifyAndReadSignaturesFprs(const Pathname &file, const Pathname &signature, bool &verifed)
+{
+ //lets be pessimistic
+ verifed = false;
+
+ if (!PathInfo( signature ).isExist())
+ return std::list<std::string>();
+
+ FILEPtr dataFile(fopen(file.c_str(), "rb"), fclose);
+ if (!dataFile)
+ return std::list<std::string>();
+
+ GpgmeDataPtr fileData(nullptr, gpgme_data_release);
+ GpgmeErr err = gpgme_data_new_from_stream (&fileData.get(), dataFile.get());
+ if (err) {
+ ERR << err << endl;
+ return std::list<std::string>();
+ }
+
+ FILEPtr sigFile(fopen(signature.c_str(), "rb"), fclose);
+ if (!sigFile) {
+ ERR << "Unable to open signature file '" << signature << "'" <<endl;
+ return std::list<std::string>();
+ }
+
+ GpgmeDataPtr sigData(nullptr, gpgme_data_release);
+ err = gpgme_data_new_from_stream (&sigData.get(), sigFile.get());
+ if (err) {
+ ERR << err << endl;
+ return std::list<std::string>();
+ }
+
+ err = gpgme_op_verify(_ctx, sigData.get(), fileData.get(), NULL);
+ if (err != GPG_ERR_NO_ERROR) {
+ ERR << err << endl;
+ return std::list<std::string>();
+ }
+
+ gpgme_verify_result_t res = gpgme_op_verify_result(_ctx);
+ if (!res || !res->signatures) {
+ ERR << "Unable to read signature fingerprints" <<endl;
+ return std::list<std::string>();
+ }
+
+ bool foundBadSignature = false;
+ std::list<std::string> signatures;
+ gpgme_signature_t sig = res->signatures;
+ while (sig) {
+
+ if (!foundBadSignature)
+ foundBadSignature = (sig->status != GPG_ERR_NO_ERROR);
+
+ if (!sig->fpr)
+ continue;
+
+ signatures.push_back(str::asString(sig->fpr));
+ sig = sig->next;
+ }
+
+ verifed = (!foundBadSignature);
+ return signatures;
+}
+
+KeyManagerCtx::Impl::~Impl()
+{
+ gpgme_release(_ctx);
+}
+
+KeyManagerCtx::Ptr KeyManagerCtx::createForOpenPGP()
+{
+ //make sure gpgpme is initialized
+ boost::call_once(gpgme_init_once, initGpgme);
+
+ gpgme_ctx_t ctx;
+ GpgmeErr err = gpgme_new(&ctx);
+ if (err != GPG_ERR_NO_ERROR) {
+ ERR << err << endl;
+ return shared_ptr<KeyManagerCtx>();
+ }
+
+ //use OpenPGP
+ err = gpgme_set_protocol(ctx, GPGME_PROTOCOL_OpenPGP);
+ if (err != GPG_ERR_NO_ERROR) {
+ ERR << err << endl;
+ gpgme_release(ctx);
+ return shared_ptr<KeyManagerCtx>();
+ }
+
+ shared_ptr<KeyManagerCtx> me( new KeyManagerCtx());
+ me->_pimpl->_ctx = ctx;
+ return me;
+}
+
+bool KeyManagerCtx::setHomedir(const Pathname &keyring_r)
+{
+
+ /* get engine information to read current state*/
+ gpgme_engine_info_t enginfo = gpgme_ctx_get_engine_info(_pimpl->_ctx);
+ if (!enginfo)
+ return false;
+
+ GpgmeErr err = gpgme_ctx_set_engine_info(
+ _pimpl->_ctx,
+ GPGME_PROTOCOL_OpenPGP,
+ enginfo->file_name,
+ keyring_r.c_str());
+
+ if (err != GPG_ERR_NO_ERROR) {
+ ERR << "Unable to set homedir " << err << endl;
+ return false;
+ }
+
+ return true;
+}
+
+Pathname KeyManagerCtx::homedir() const
+{
+ gpgme_engine_info_t enginfo = gpgme_ctx_get_engine_info(_pimpl->_ctx);
+ if (!enginfo)
+ return Pathname();
+
+ return Pathname(enginfo->home_dir);
+}
+
+std::list<PublicKeyData> KeyManagerCtx::listKeys()
+{
+ std::list<PublicKeyData> keys;
+ gpgme_key_t key;
+ GpgmeErr err = GPG_ERR_NO_ERROR;
+
+ gpgme_keylist_mode_t mode = GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_SIGS;
+ gpgme_set_keylist_mode (_pimpl->_ctx, mode);
+ gpgme_op_keylist_start (_pimpl->_ctx, NULL, 0);
+
+ while (!(err = gpgme_op_keylist_next(_pimpl->_ctx, &key))) {
+ PublicKeyData data = PublicKeyData::fromGpgmeKey(key);
+ if (data) {
+ keys.push_back(data);
+ }
+ gpgme_key_release(key);
+ }
+ gpgme_op_keylist_end(_pimpl->_ctx);
+ return keys;
+}
+
+std::list<PublicKeyData> KeyManagerCtx::readKeyFromFile(const Pathname &file)
+{
+ //seems GPGME does not support reading keys from a keyfile using
+ //gpgme_data_t and gpgme_op_keylist_from_data_start, this always
+ //return unsupported errors. However importing and listing the key works.
+ zypp::Pathname realHomedir = homedir();
+
+ zypp::filesystem::TmpDir tmpKeyring;
+ if (!setHomedir(tmpKeyring.path()))
+ return std::list<PublicKeyData>();
+
+ if (!importKey(file)) {
+ setHomedir(realHomedir);
+ return std::list<PublicKeyData>();
+ }
+
+ std::list<PublicKeyData> keys = listKeys();
+ setHomedir(realHomedir);
+ return keys;
+}
+
+bool KeyManagerCtx::verify(const Pathname &file, const Pathname &signature)
+{
+ if ( !PathInfo( file ).isExist() || !PathInfo( signature ).isExist() )
+ return false;
+
+ bool verified = false;
+ _pimpl->verifyAndReadSignaturesFprs(file, signature, verified);
+ return verified;
+}
+
+bool KeyManagerCtx::exportKey(const std::string &id, std::ostream &stream)
+{
+ GpgmeErr err = GPG_ERR_NO_ERROR;
+
+ GpgmeKeyPtr foundKey;
+
+ //search for requested key id
+ gpgme_key_t key;
+ gpgme_op_keylist_start(_pimpl->_ctx, NULL, 0);
+ while (!(err = gpgme_op_keylist_next(_pimpl->_ctx, &key))) {
+ if (key->subkeys && id == str::asString(key->subkeys->keyid)) {
+ GpgmeKeyPtr(key, gpgme_key_release).swap(foundKey);
+ break;
+ }
+ gpgme_key_release(key);
+ }
+ gpgme_op_keylist_end(_pimpl->_ctx);
+
+ if (!foundKey) {
+ WAR << "Key " << id << "not found" << endl;
+ return false;
+ }
+
+ //function needs a array of keys to export
+ gpgme_key_t keyarray[2];
+ keyarray[0] = foundKey.get();
+ keyarray[1] = NULL;
+
+ GpgmeDataPtr out(nullptr, gpgme_data_release);
+ err = gpgme_data_new (&out.get());
+ if (err) {
+ ERR << err << endl;
+ return false;
+ }
+
+ //format as ascii armored
+ gpgme_set_armor (_pimpl->_ctx, 1);
+ err = gpgme_op_export_keys (_pimpl->_ctx, keyarray, 0, out.get());
+ if (!err) {
+ int ret = gpgme_data_seek (out.get(), 0, SEEK_SET);
+ if (ret) {
+ ERR << "Unable to seek in exported key data" << endl;
+ return false;
+ }
+
+ const int bufsize = 512;
+ char buf[bufsize + 1];
+ while ((ret = gpgme_data_read(out.get(), buf, bufsize)) > 0) {
+ stream.write(buf, ret);
+ }
+
+ //failed to read from buffer
+ if (ret < 0) {
+ ERR << "Unable to read exported key data" << endl;
+ return false;
+ }
+ } else {
+ ERR << "Error exporting key: "<< err << endl;
+ return false;
+ }
+
+ //if we reach this point export was successful
+ return true;
+}
+
+bool KeyManagerCtx::importKey(const Pathname &keyfile)
+{
+ if ( !PathInfo( keyfile ).isExist() ) {
+ ERR << "Keyfile '" << keyfile << "' does not exist.";
+ return false;
+ }
+
+ GpgmeDataPtr data(nullptr, gpgme_data_release);
+ GpgmeErr err;
+
+ err = gpgme_data_new_from_file(&data.get(), keyfile.c_str(), 1);
+ if (err) {
+ ERR << "Error importing key: "<< err << endl;
+ return false;
+ }
+
+ err = gpgme_op_import(_pimpl->_ctx, data.get());
+ if (err) {
+ ERR << "Error importing key: "<< err << endl;
+ }
+ return (err == GPG_ERR_NO_ERROR);
+}
+
+bool KeyManagerCtx::deleteKey(const std::string &id)
+{
+ gpgme_key_t key;
+ GpgmeErr err = GPG_ERR_NO_ERROR;
+
+ gpgme_op_keylist_start(_pimpl->_ctx, NULL, 0);
+
+ while (!(err = gpgme_op_keylist_next(_pimpl->_ctx, &key))) {
+ if (key->subkeys && id == str::asString(key->subkeys->keyid)) {
+ err = gpgme_op_delete(_pimpl->_ctx, key, 0);
+
+ gpgme_key_release(key);
+ gpgme_op_keylist_end(_pimpl->_ctx);
+
+ if (err) {
+ ERR << "Error deleting key: "<< err << endl;
+ return false;
+ }
+ return true;
+ }
+ gpgme_key_release(key);
+ }
+
+ gpgme_op_keylist_end(_pimpl->_ctx);
+ WAR << "Key: '"<< id << "' not found." << endl;
+ return false;
+}
+
+std::list<std::string> KeyManagerCtx::readSignatureFingerprints(const Pathname &signature)
+{
+ //gpgme needs a dummy file to read signatures from a detached sig file
+ //verification will fail but we get all signatures
+ zypp::filesystem::TmpFile dummyFile;
+
+ bool verified = false;
+ return _pimpl->verifyAndReadSignaturesFprs(dummyFile.path(), signature, verified);
+}
+
+}
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ V /| _/ _/ |
+| / /__ | | | | | | |
+| /_____||_| |_| |_| |
+| |
+\---------------------------------------------------------------------*/
+/** \file zypp/KeyManager.h
+ *
+*/
+#ifndef ZYPP_KEYMANAGER_H
+#define ZYPP_KEYMANAGER_H
+
+#include "zypp/base/PtrTypes.h"
+#include "zypp/Pathname.h"
+#include "zypp/PublicKey.h"
+
+#include <memory>
+
+namespace zypp
+{
+
+ ///////////////////////////////////////////////////////////////////
+ /// \class KeyManagerCtx::KeyManagerCtx
+ /// \brief Wrapper for GPGME
+ ///
+ /// Encapsulates all calls to the gpgme library, each instance
+ /// represents a context of operations on the specified keyring.
+ ///////////////////////////////////////////////////////////////////
+class KeyManagerCtx
+{
+ public:
+ typedef shared_ptr<KeyManagerCtx> Ptr;
+
+ /** Creates a new KeyManagerCtx for PGP */
+ static Ptr createForOpenPGP();
+
+ /** Changes the keyring directory */
+ bool setHomedir (const Pathname & keyring_r);
+ Pathname homedir ()const;
+
+ /** Returns a list of all public keys found in the current keyring */
+ std::list<PublicKeyData> listKeys();
+
+ /** Returns a list of all \sa PublicKeyData found in \a file */
+ std::list<PublicKeyData> readKeyFromFile(const Pathname & file);
+
+ /** Tries to verify \a file using \a signature, returns true on success */
+ bool verify(const Pathname & file, const Pathname & signature);
+
+ /** Exports the key with \a id into the given \a stream, returns true on success */
+ bool exportKey(const std::string & id, std::ostream & stream);
+
+ /** Tries to import a key from \a keyfile, returns true on success */
+ bool importKey(const Pathname & keyfile);
+
+ /** Tries to delete a key specified by \a id, returns true on success */
+ bool deleteKey (const std::string & id);
+
+ /** Reads all fingerprints from the \a signature file , returns a list of all found fingerprints */
+ std::list<std::string> readSignatureFingerprints(const Pathname & signature);
+
+ private:
+ class Impl;
+
+ KeyManagerCtx();
+
+ RW_pointer<Impl> _pimpl; ///< Pointer to implementation
+
+};
+
+}
+
+
+#endif
#include "zypp/ExternalProgram.h"
#include "zypp/TmpPath.h"
#include "zypp/ZYppCallbacks.h" // JobReport::instance
+#include "zypp/KeyManager.h"
using std::endl;
#undef ZYPP_BASE_LOGGER_LOGGROUP
#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::KeyRing"
-/** \todo Fix duplicate define in PublicKey/KeyRing */
-#define GPG_BINARY "/usr/bin/gpg2"
-
///////////////////////////////////////////////////////////////////
namespace zypp
{ /////////////////////////////////////////////////////////////////
const std::list<PublicKeyData> & getData( const Pathname & keyring_r, Cache & cache_r ) const
{
- if ( cache_r.hasChanged() )
- {
- const char* argv[] =
- {
- GPG_BINARY,
- "--list-public-keys",
- "--homedir", keyring_r.c_str(),
- "--no-default-keyring",
- "--quiet",
- "--with-colons",
- "--fixed-list-mode",
- "--with-fingerprint",
- "--with-sig-list",
- "--no-tty",
- "--no-greeting",
- "--batch",
- "--status-fd", "1",
- NULL
- };
-
- PublicKeyScanner scanner;
- ExternalProgram prog( argv ,ExternalProgram::Discard_Stderr, false, -1, true );
- for( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
- {
- scanner.scan( line );
- }
- prog.close();
-
- cache_r._data.swap( scanner._keys );
- MIL << "Found keys: " << cache_r._data << endl;
- }
- return cache_r._data;
+ if ( cache_r.hasChanged() ) {
+ shared_ptr<KeyManagerCtx> ctx = KeyManagerCtx::createForOpenPGP();
+ if (ctx) {
+ if (ctx->setHomedir(keyring_r)) {
+ std::list<PublicKeyData> foundKeys = ctx->listKeys();
+ cache_r._data.swap(foundKeys);
+ }
+ }
+ MIL << "Found keys: " << cache_r._data << endl;
+ }
+ return cache_r._data;
}
mutable CacheMap _cacheMap;
void KeyRing::Impl::dumpPublicKey( const std::string & id, const Pathname & keyring, std::ostream & stream )
{
- const char* argv[] =
- {
- GPG_BINARY,
- "-a",
- "--export",
- "--homedir", keyring.asString().c_str(),
- "--no-default-keyring",
- "--quiet",
- "--no-tty",
- "--no-greeting",
- "--no-permission-warning",
- "--batch",
- id.c_str(),
- NULL
- };
- ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
- for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
- {
- stream << line;
- }
- prog.close();
+ KeyManagerCtx::Ptr ctx = KeyManagerCtx::createForOpenPGP();
+ if (!ctx || !ctx->setHomedir(keyring))
+ return;
+ ctx->exportKey(id, stream);
}
filesystem::TmpFile KeyRing::Impl::dumpPublicKeyToTmp( const std::string & id, const Pathname & keyring )
% keyfile.asString()
% keyring.asString() ));
- const char* argv[] =
- {
- GPG_BINARY,
- "--import",
- "--homedir", keyring.asString().c_str(),
- "--no-default-keyring",
- "--quiet",
- "--no-tty",
- "--no-greeting",
- "--no-permission-warning",
- "--status-fd", "1",
- keyfile.asString().c_str(),
- NULL
- };
+ KeyManagerCtx::Ptr ctx = KeyManagerCtx::createForOpenPGP();
+ if(!ctx || !ctx->setHomedir(keyring))
+ ZYPP_THROW(KeyRingException(_("Failed to import key.")));
cachedPublicKeyData.setDirty( keyring );
- ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
- if ( prog.close() )
+ if(!ctx->importKey(keyfile))
ZYPP_THROW(KeyRingException(_("Failed to import key.")));
}
void KeyRing::Impl::deleteKey( const std::string & id, const Pathname & keyring )
{
- const char* argv[] =
- {
- GPG_BINARY,
- "--delete-keys",
- "--homedir", keyring.asString().c_str(),
- "--no-default-keyring",
- "--yes",
- "--quiet",
- "--no-tty",
- "--batch",
- "--status-fd", "1",
- id.c_str(),
- NULL
- };
+ KeyManagerCtx::Ptr ctx = KeyManagerCtx::createForOpenPGP();
+ if(!ctx) {
+ ZYPP_THROW(KeyRingException(_("Failed to delete key.")));
+ }
- cachedPublicKeyData.setDirty( keyring );
- ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
- if ( prog.close() )
+ if(!ctx->setHomedir(keyring)) {
ZYPP_THROW(KeyRingException(_("Failed to delete key.")));
+ }
+
+ if(!ctx->deleteKey(id)){
+ ZYPP_THROW(KeyRingException(_("Failed to delete key.")));
+ }
+
+ cachedPublicKeyData.setDirty( keyring );
}
std::string KeyRing::Impl::readSignatureKeyId( const Pathname & signature )
ZYPP_THROW(KeyRingException( str::Format(_("Signature file %s not found")) % signature.asString() ));
MIL << "Determining key id of signature " << signature << endl;
- const char* argv[] =
- {
- GPG_BINARY,
- "--list-packets",
- signature.asString().c_str(),
- NULL
- };
- ExternalProgram prog( argv ,ExternalProgram::Discard_Stderr, false, -1, true );
-
- // :signature packet: algo 1, keyid 1397BC53640DB551
- // version 4, created 1501094968, md5len 0, sigclass 0x00
- // digest algo 8, begin of digest 15 89
- // hashed subpkt 2 len 4 (sig created 2017-07-26)
- // subpkt 16 len 8 (issuer key ID 1397BC53640DB551)
- // data: [4095 bits]
- std::string id;
- for( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
- {
- if ( id.empty() && str::startsWith( line, ":signature packet:" ) )
- {
- static const str::regex rxKeyId( " keyid +([0-9A-Z]+)" );
- str::smatch what;
- if( str::regex_match( line, what, rxKeyId ) )
- id = what[1];
- }
+
+ KeyManagerCtx::Ptr ctx = KeyManagerCtx::createForOpenPGP();
+ if(!ctx) {
+ return std::string();
}
- MIL << "Determined key id [" << id << "] for signature " << signature << endl;
- prog.close();
- return id;
+ std::list<std::string> fprs = ctx->readSignatureFingerprints(signature);
+ if (fprs.size()) {
+ std::string &id = fprs.back();
+ MIL << "Determined key id [" << id << "] for signature " << signature << endl;
+ return id;
+ }
+ return std::string();
}
bool KeyRing::Impl::verifyFile( const Pathname & file, const Pathname & signature, const Pathname & keyring )
{
- const char* argv[] =
- {
- GPG_BINARY,
- "--verify",
- "--homedir", keyring.asString().c_str(),
- "--no-default-keyring",
- "--quiet",
- "--no-tty",
- "--batch",
- "--no-greeting",
- "--status-fd", "1",
- signature.asString().c_str(),
- file.asString().c_str(),
- NULL
- };
-
- // no need to parse output for now
- // [GNUPG:] SIG_ID yCc4u223XRJnLnVAIllvYbUd8mQ 2006-03-29 1143618744
- // [GNUPG:] GOODSIG A84EDAE89C800ACA SuSE Package Signing Key <build@suse.de>
- // gpg: Good signature from "SuSE Package Signing Key <build@suse.de>"
- // [GNUPG:] VALIDSIG 79C179B2E1C820C1890F9994A84EDAE89C800ACA 2006-03-29 1143618744 0 3 0 17 2 00 79C179B2E1C820C1890F9994A84EDAE89C800ACA
- // [GNUPG:] TRUST_UNDEFINED
-
- // [GNUPG:] ERRSIG A84EDAE89C800ACA 17 2 00 1143618744 9
- // [GNUPG:] NO_PUBKEY A84EDAE89C800ACA
-
- ExternalProgram prog( argv,ExternalProgram::Discard_Stderr, false, -1, true );
+ KeyManagerCtx::Ptr ctx = KeyManagerCtx::createForOpenPGP();
+ if (!ctx || !ctx->setHomedir(keyring))
+ return false;
- return ( prog.close() == 0 ) ? true : false;
+ return ctx->verify(file, signature);
}
///////////////////////////////////////////////////////////////////
#include "zypp/base/Exception.h"
#include "zypp/base/LogTools.h"
#include "zypp/Date.h"
+#include "zypp/KeyManager.h"
-/** \todo Fix duplicate define in PublicKey/KeyRing */
-#define GPG_BINARY "/usr/bin/gpg2"
+#include <gpgme.h>
using std::endl;
+#undef ZYPP_BASE_LOGGER_LOGGROUP
+#define ZYPP_BASE_LOGGER_LOGGROUP "zypp::gpg"
+
///////////////////////////////////////////////////////////////////
namespace zypp
{
} //namespace
///////////////////////////////////////////////////////////////////
+
///////////////////////////////////////////////////////////////////
/// \class PublicSubkeyData::Impl
/// \brief PublicSubkeyData implementation.
///////////////////////////////////////////////////////////////////
+
struct PublicSubkeyData::Impl
{
std::string _id;
public:
/** Offer default Impl. */
- static shared_ptr<Impl> nullimpl()
- {
- static shared_ptr<Impl> _nullimpl( new Impl );
- return _nullimpl;
- }
+ static shared_ptr<Impl> nullimpl();
private:
friend Impl * rwcowClone<Impl>( const Impl * rhs );
/** clone for RWCOW_pointer */
- Impl * clone() const
- { return new Impl( *this ); }
+ Impl * clone() const;
};
+ shared_ptr<zypp::PublicSubkeyData::Impl> PublicSubkeyData::Impl::nullimpl()
+ {
+ static shared_ptr<Impl> _nullimpl( new Impl );
+ return _nullimpl;
+ }
+
+ zypp::PublicSubkeyData::Impl *PublicSubkeyData::Impl::clone() const
+ {
+ return new Impl( *this );
+ }
+
///////////////////////////////////////////////////////////////////
/// class PublicSubkeyData
///////////////////////////////////////////////////////////////////
: _pimpl( Impl::nullimpl() )
{}
+ PublicSubkeyData::PublicSubkeyData(const _gpgme_subkey *rawSubKeyData)
+ : _pimpl (new Impl)
+ {
+ _pimpl->_created = zypp::Date(rawSubKeyData->timestamp);
+ _pimpl->_expires = zypp::Date(rawSubKeyData->expires);
+ _pimpl->_id = str::asString(rawSubKeyData->keyid);
+ }
+
PublicSubkeyData::~PublicSubkeyData()
{}
/// \class PublicKeyData::Impl
/// \brief PublicKeyData implementation.
///////////////////////////////////////////////////////////////////
+ ///
struct PublicKeyData::Impl
{
std::string _id;
std::vector<PublicSubkeyData> _subkeys;
public:
- bool hasSubkeyId( const std::string & id_r ) const
- {
- bool ret = false;
- for ( const PublicSubkeyData & sub : _subkeys )
- {
- if ( sub.id() == id_r )
- {
- ret = true;
- break;
- }
- }
- return ret;
- }
+ bool hasSubkeyId( const std::string & id_r ) const;
public:
/** Offer default Impl. */
- static shared_ptr<Impl> nullimpl()
- {
- static shared_ptr<Impl> _nullimpl( new Impl );
- return _nullimpl;
- }
+ static shared_ptr<Impl> nullimpl();
+ static shared_ptr<Impl> fromGpgmeKey(gpgme_key_t rawData);
private:
friend Impl * rwcowClone<Impl>( const Impl * rhs );
/** clone for RWCOW_pointer */
- Impl * clone() const
- { return new Impl( *this ); }
+ Impl * clone() const;
};
+ bool PublicKeyData::Impl::hasSubkeyId(const std::string &id_r) const
+ {
+ bool ret = false;
+ for ( const PublicSubkeyData & sub : _subkeys )
+ {
+ if ( sub.id() == id_r )
+ {
+ ret = true;
+ break;
+ }
+ }
+ return ret;
+ }
+
+ shared_ptr<PublicKeyData::Impl> PublicKeyData::Impl::nullimpl()
+ {
+ static shared_ptr<Impl> _nullimpl( new Impl );
+ return _nullimpl;
+ }
+
+ shared_ptr<PublicKeyData::Impl> PublicKeyData::Impl::fromGpgmeKey(gpgme_key_t rawData)
+ {
+ //gpgpme stores almost nothing in the top level key
+ //the information we look for is stored in the subkey, where subkey[0]
+ //is always the primary key
+ gpgme_subkey_t sKey = rawData->subkeys;
+ if (sKey) {
+ shared_ptr<PublicKeyData::Impl> data(new Impl);
+ //libzypp expects the date of the first signature on the first uid
+ if(rawData->uids && rawData->uids->signatures)
+ data->_created = zypp::Date(rawData->uids->signatures->timestamp);
+ else
+ data->_created = zypp::Date(sKey->timestamp);
+
+ data->_expires = zypp::Date(sKey->expires);
+ data->_fingerprint = str::asString(sKey->fpr);
+ data->_id = str::asString(sKey->keyid);
+
+ //get the primary user ID
+ if (rawData->uids) {
+ data->_name = str::asString(rawData->uids->uid);
+ }
+
+ //the rest of the keys
+ sKey = sKey->next;
+ while (sKey) {
+ data->_subkeys.push_back( PublicSubkeyData(sKey) );
+ sKey = sKey->next;
+ }
+ return data;
+ }
+ return nullimpl();
+ }
+
+ zypp::PublicKeyData::Impl *PublicKeyData::Impl::clone() const
+ {
+ return new Impl( *this );
+ }
+
///////////////////////////////////////////////////////////////////
/// class PublicKeyData
///////////////////////////////////////////////////////////////////
: _pimpl( Impl::nullimpl() )
{}
+ PublicKeyData::PublicKeyData(shared_ptr<Impl> data)
+ : _pimpl( data )
+ {}
+
PublicKeyData::~PublicKeyData()
{}
+ PublicKeyData PublicKeyData::fromGpgmeKey(_gpgme_key *data)
+ { return PublicKeyData(Impl::fromGpgmeKey(data)); }
+
PublicKeyData::operator bool() const
{ return !_pimpl->_fingerprint.empty(); }
///////////////////////////////////////////////////////////////////
- /// \class PublicKeyScanner::Impl
- /// \brief PublicKeyScanner implementation.
- ///////////////////////////////////////////////////////////////////
- struct PublicKeyScanner::Impl
- {
- enum { pNONE, pPUB, pSIG, pFPR, pUID, pSUB } _parseEntry;
- std::vector<std::string> _words;
- PublicKeyData::Impl * _keyDataPtr;
-
- Impl()
- : _parseEntry( pNONE )
- , _keyDataPtr( nullptr )
- {}
-
- void scan( std::string & line_r, std::list<PublicKeyData> & keys_r )
- {
- // pub:-:1024:17:A84EDAE89C800ACA:971961473:1214043198::-:SuSE Package Signing Key <build@suse.de>:
- // fpr:::::::::79C179B2E1C820C1890F9994A84EDAE89C800ACA:
- // sig:::17:A84EDAE89C800ACA:1087899198:::::[selfsig]::13x:
- // sig:::17:9E40E310000AABA4:980442706::::[User ID not found]:10x:
- // sig:::1:77B2E6003D25D3D9:980443247::::[User ID not found]:10x:
- // sig:::17:A84EDAE89C800ACA:1318348291:::::[selfsig]::13x:
- // sub:-:2048:16:197448E88495160C:971961490:1214043258::: [expires: 2008-06-21]
- // sig:::17:A84EDAE89C800ACA:1087899258:::::[keybind]::18x:
- if ( line_r.empty() )
- return;
-
- // quick check for interesting entries, no parsing in subkeys
- _parseEntry = pNONE;
- switch ( line_r[0] )
- {
- case 'p':
- if ( line_r[1] == 'u' && line_r[2] == 'b' && line_r[3] == ':' )
- {
- _parseEntry = pPUB;
- keys_r.push_back( PublicKeyData() ); // reset upon new key
- _keyDataPtr = keys_r.back()._pimpl.get();
- }
- break;
-
- case 'f':
- if ( line_r[1] == 'p' && line_r[2] == 'r' && line_r[3] == ':' )
- _parseEntry = pFPR;
- break;
-
- case 'u':
- if ( line_r[1] == 'i' && line_r[2] == 'd' && line_r[3] == ':' )
- _parseEntry = pUID;
- break;
-
- case 's':
- if ( line_r[1] == 'i' && line_r[2] == 'g' && line_r[3] == ':' )
- _parseEntry = pSIG;
- else if ( line_r[1] == 'u' && line_r[2] == 'b' && line_r[3] == ':' )
- _parseEntry = pSUB;
- break;
-
- default:
- return;
- }
- if ( _parseEntry == pNONE )
- return;
- if ( ! ( _keyDataPtr->_subkeys.empty() || _parseEntry == pSUB ) )
- return; // collecting subkeys only
-
- if ( line_r[line_r.size()-1] == '\n' )
- line_r.erase( line_r.size()-1 );
- //DBG << line_r << endl;
-
- _words.clear();
- str::splitFields( line_r, std::back_inserter(_words), ":" );
-
- switch ( _parseEntry )
- {
- case pPUB:
- _keyDataPtr->_id = _words[4];
- _keyDataPtr->_name = str::replaceAll( _words[9], "\\x3a", ":" );
- _keyDataPtr->_created = Date(str::strtonum<Date::ValueType>(_words[5]));
- _keyDataPtr->_expires = Date(str::strtonum<Date::ValueType>(_words[6]));
- break;
-
- case pSIG:
- // Update creation/modification date from signatures type "13x".
- if ( ( _words.size() > 10 && _words[10] == "13x" && !_words[9].empty() && _words[9] != "[User ID not found]" )
- || ( _words.size() > 12 && _words[12] == "13x" /* [selfsig] */) )
- {
- Date cdate(str::strtonum<Date::ValueType>(_words[5]));
- if ( _keyDataPtr->_created < cdate )
- _keyDataPtr->_created = cdate;
- }
- break;
-
- case pFPR:
- if ( _keyDataPtr->_fingerprint.empty() )
- _keyDataPtr->_fingerprint = _words[9];
- break;
-
- case pUID:
- if ( ! _words[9].empty() && _words[9] != "[User ID not found]" )
- _keyDataPtr->_name = str::replaceAll( _words[9], "\\x3a", ":" );
- break;
-
- case pSUB:
- _keyDataPtr->_subkeys.push_back( PublicSubkeyData() );
- {
- PublicSubkeyData::Impl * subPtr = _keyDataPtr->_subkeys.back()._pimpl.get();
- subPtr->_id = _words[4];
- subPtr->_created = Date(str::strtonum<Date::ValueType>(_words[5]));
- subPtr->_expires = Date(str::strtonum<Date::ValueType>(_words[6]));
- }
- break;
-
- case pNONE:
- break; // intentionally no default:
- }
- }
- };
- ///////////////////////////////////////////////////////////////////
-
- ///////////////////////////////////////////////////////////////////
- // class PublicKeyScanner
- ///////////////////////////////////////////////////////////////////
-
- PublicKeyScanner::PublicKeyScanner()
- : _pimpl( new Impl )
- {}
-
- PublicKeyScanner::~PublicKeyScanner()
- {}
-
- void PublicKeyScanner::scan( std::string line_r )
- { _pimpl->scan( line_r, _keys ); }
-
-
- ///////////////////////////////////////////////////////////////////
/// \class PublicKey::Impl
/// \brief PublicKey implementation.
///////////////////////////////////////////////////////////////////
PathInfo info( path() );
MIL << "Reading pubkey from " << info.path() << " of size " << info.size() << " and sha1 " << filesystem::checksum(info.path(), "sha1") << endl;
- static std::string tmppath( _initHomeDir() );
- std::string datapath( path().asString() );
+ //@TODO is this still required? KeyManagerCtx creates a homedir on the fly
+ static std::string tmppath( _initHomeDir() );
- const char* argv[] =
- {
- GPG_BINARY,
- "-v",
- "--no-default-keyring",
- "--fixed-list-mode",
- "--with-fingerprint",
- "--with-colons",
- "--homedir",
- tmppath.c_str(),
- "--quiet",
- "--no-tty",
- "--no-greeting",
- "--batch",
- "--status-fd", "1",
- datapath.c_str(),
- NULL
- };
- ExternalProgram prog( argv, ExternalProgram::Discard_Stderr, false, -1, true );
-
- PublicKeyScanner scanner;
- for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
- {
- scanner.scan( line );
- }
- int ret = prog.close();
-
- switch ( scanner._keys.size() )
- {
- case 0:
- if ( ret == 129 )
- ZYPP_THROW( Exception( std::string("Can't read public key data: ") + GPG_BINARY + " is not installed!" ) );
- else
- ZYPP_THROW( BadKeyException( "File " + path().asString() + " doesn't contain public key data" , path() ) );
- break;
-
- case 1:
- // ok.
- _keyData = scanner._keys.back();
- _hiddenKeys.clear();
- break;
-
- default:
- WAR << "File " << path().asString() << " contains multiple keys: " << scanner._keys << endl;
- _keyData = scanner._keys.back();
- scanner._keys.pop_back();
- _hiddenKeys.swap( scanner._keys );
- break;
- }
+ KeyManagerCtx::Ptr ctx = KeyManagerCtx::createForOpenPGP();
+ if (!ctx || !ctx->setHomedir(tmppath)) {
+ ZYPP_THROW( Exception( std::string("Can't read public key data: Setting the keyring path failed!")) );
+ }
- MIL << "Read pubkey from " << info.path() << ": " << _keyData << endl;
+ std::list<PublicKeyData> keys = ctx->readKeyFromFile(path());
+ switch ( keys.size() )
+ {
+ case 0:
+ ZYPP_THROW( BadKeyException( "File " + path().asString() + " doesn't contain public key data" , path() ) );
+ break;
+
+ case 1:
+ // ok.
+ _keyData = keys.back();
+ _hiddenKeys.clear();
+ break;
+
+ default:
+ WAR << "File " << path().asString() << " contains multiple keys: " << keys << endl;
+ _keyData = keys.back();
+ keys.pop_back();
+ _hiddenKeys.swap( keys );
+ break;
+ }
+
+ MIL << "Read pubkey from " << info.path() << ": " << _keyData << endl;
}
private:
// class PublicKey
///////////////////////////////////////////////////////////////////
PublicKey::PublicKey()
- : _pimpl( Impl::nullimpl() )
+ : _pimpl( Impl::nullimpl() )
{}
PublicKey::PublicKey( const Pathname & file )
std::ostream & dumpOn( std::ostream & str, const PublicKey & obj )
{ return dumpOn( str, obj.keyData() ); }
+
+
+
/////////////////////////////////////////////////////////////////
} // namespace zypp
///////////////////////////////////////////////////////////////////
#include "zypp/Edition.h"
#include "zypp/Date.h"
+struct _gpgme_key;
+struct _gpgme_subkey;
+
///////////////////////////////////////////////////////////////////
namespace zypp
{ /////////////////////////////////////////////////////////////////
class TmpFile;
}
class PublicKeyData;
+ class KeyManagerCtx;
///////////////////////////////////////////////////////////////////
/// \class BadKeyException
private:
class Impl;
RWCOW_pointer<Impl> _pimpl;
- friend class PublicKeyScanner;
+ friend class PublicKeyData;
friend std::ostream & dumpOn( std::ostream & str, const PublicKeyData & obj );
+ PublicSubkeyData(const _gpgme_subkey *rawSubKeyData);
};
///////////////////////////////////////////////////////////////////
private:
class Impl;
RWCOW_pointer<Impl> _pimpl;
- friend class PublicKeyScanner;
+
+ friend class KeyManagerCtx;
+ static PublicKeyData fromGpgmeKey(_gpgme_key *data);
+
+ PublicKeyData(shared_ptr<Impl> data);
friend std::ostream & dumpOn( std::ostream & str, const PublicKeyData & obj );
};
///////////////////////////////////////////////////////////////////
{ return !( lhs == rhs ); }
///////////////////////////////////////////////////////////////////
- /// \class PublicKeyScanner
- /// \brief Scan abstract from 'gpg --with-colons' key listings.
- /// Feed gpg output line by line into \ref scan. The collected \ref PublicKeyData
- /// contain the keys data (fingerprint, uid,...) but not the key itself (ASCII
- /// armored stored in a file).
- /// \code
- /// std::list<PublicKeyData> result;
- /// {
- /// PublicKeyScanner scanner;
- /// for ( std::string line = prog.receiveLine(); !line.empty(); line = prog.receiveLine() )
- /// scanner.scan( line );
- /// result.swap( scanner._keys );
- /// }
- /// \endcode
- /// \relates PublicKeyData
- ///////////////////////////////////////////////////////////////////
- struct PublicKeyScanner
- {
- PublicKeyScanner();
- ~PublicKeyScanner();
-
- /** Feed gpg output line by line into \ref scan. */
- void scan( std::string line_r );
-
- /** Extracted keys. */
- std::list<PublicKeyData> _keys;
-
- private:
- class Impl;
- RW_pointer<Impl, rw_pointer::Scoped<Impl> > _pimpl;
- };
- ///////////////////////////////////////////////////////////////////
-
-
- ///////////////////////////////////////////////////////////////////
/// \class PublicKey
/// \brief Class representing one GPG Public Key (PublicKeyData + ASCII armored in a tempfile).
///
#endif
inline std::string asString( const char * t )
- { return t; }
+ { return t == nullptr ? std::string() : t; }
inline std::string asString( char * t )
- { return t; }
+ { return t == nullptr ? std::string() : t; }
template<class Tp>
inline std::string asString( const Tp &t )
//TODO: make configurable
list<string> filesystems;
- // if DVD, try UDF filesystem before iso9660
+ filesystems.push_back("iso9660");
+
+ // if DVD, try UDF filesystem after iso9660
if ( _url.getScheme() == "dvd" )
filesystems.push_back("udf");
- filesystems.push_back("iso9660");
-
// try all devices in sequence
int count = 0;
std::string mountpoint( attachPoint().asString() );
#include <iostream>
#include <fstream>
#include <unordered_set>
+#include <iterator>
+#include <stdio.h>
#include "zypp/base/LogTools.h"
#include "zypp/base/String.h"
#include "zypp/base/Gettext.h"
/** lsof output line + files extracted so far for this PID */
typedef std::pair<std::string,std::unordered_set<std::string>> CacheEntry;
- /** Add \c cache to \c data if the process is accessing deleted files.
- * \c pid string in \c cache is the proc line \c (pcuLR), \c files
- * are already in place. Always clear the \c cache.files!
- */
- inline void addDataIf( std::vector<CheckAccessDeleted::ProcInfo> & data_r, const CacheEntry & cache_r )
+ /////////////////////////////////////////////////////////////////
+ /// \class FilterRunsInLXC
+ /// \brief Functor guessing whether \a PID is running in a container.
+ ///
+ /// Assumme using different \c pid namespace than \c self.
+ /////////////////////////////////////////////////////////////////
+ struct FilterRunsInLXC
{
- const auto & filelist( cache_r.second );
+ bool operator()( pid_t pid_r ) const
+ { return( nsIno( pid_r, "pid" ) != pidNS ); }
- if ( filelist.empty() )
- return;
+ FilterRunsInLXC()
+ : pidNS( nsIno( "self", "pid" ) )
+ {}
- // at least one file access so keep it:
- data_r.push_back( CheckAccessDeleted::ProcInfo() );
- CheckAccessDeleted::ProcInfo & pinfo( data_r.back() );
- pinfo.files.insert( pinfo.files.begin(), filelist.begin(), filelist.end() );
+ static inline ino_t nsIno( const std::string & pid_r, const std::string & ns_r )
+ { return PathInfo("/proc/"+pid_r+"/ns/"+ns_r).ino(); }
- const std::string & pline( cache_r.first );
- std::string commandname; // pinfo.command if still needed...
- for_( ch, pline.begin(), pline.end() )
- {
- switch ( *ch )
- {
- case 'p':
- pinfo.pid = &*(ch+1);
- break;
- case 'R':
- pinfo.ppid = &*(ch+1);
- break;
- case 'u':
- pinfo.puid = &*(ch+1);
- break;
- case 'L':
- pinfo.login = &*(ch+1);
- break;
- case 'c':
- if ( pinfo.command.empty() )
- commandname = &*(ch+1);
- break;
- }
- if ( *ch == '\n' ) break; // end of data
- do { ++ch; } while ( *ch != '\0' ); // skip to next field
- }
+ static inline ino_t nsIno( pid_t pid_r, const std::string & ns_r )
+ { return nsIno( asString(pid_r), ns_r ); }
- if ( pinfo.command.empty() )
- {
- // the lsof command name might be truncated, so we prefer /proc/<pid>/exe
- pinfo.command = filesystem::readlink( Pathname("/proc")/pinfo.pid/"exe" ).basename();
- if ( pinfo.command.empty() )
- pinfo.command = std::move(commandname);
- }
- }
+ ino_t pidNS;
+ };
+ } //namespace
+ /////////////////////////////////////////////////////////////////
+
+ class CheckAccessDeleted::Impl
+ {
+ public:
+ CheckAccessDeleted::Impl *clone() const;
+ bool addDataIf( const CacheEntry & cache_r, std::vector<std::string> *debMap = nullptr );
+ void addCacheIf( CacheEntry & cache_r, const std::string & line_r, std::vector<std::string> *debMap = nullptr );
- /** Add file to cache if it refers to a deleted executable or library file:
- * - Either the link count \c(k) is \c 0, or no link cout is present.
- * - The type \c (t) is set to \c REG or \c DEL
- * - The filedescriptor \c (f) is set to \c txt, \c mem or \c DEL
- */
- inline void addCacheIf( CacheEntry & cache_r, const std::string & line_r, bool verbose_r )
- {
- const char * f = 0;
- const char * t = 0;
- const char * n = 0;
+ std::map<pid_t,CacheEntry> filterInput( externalprogram::ExternalDataSource &source );
+ CheckAccessDeleted::size_type createProcInfo( const std::map<pid_t,CacheEntry> &in );
- for_( ch, line_r.c_str(), ch+line_r.size() )
- {
- switch ( *ch )
- {
- case 'k':
- if ( *(ch+1) != '0' ) // skip non-zero link counts
- return;
- break;
- case 'f':
- f = ch+1;
- break;
- case 't':
- t = ch+1;
- break;
- case 'n':
- n = ch+1;
- break;
- }
- if ( *ch == '\n' ) break; // end of data
- do { ++ch; } while ( *ch != '\0' ); // skip to next field
- }
+ std::vector<CheckAccessDeleted::ProcInfo> _data;
+ bool _fromLsofFileMode = false; // Set if we currently process data from a debug file
+ bool _verbose = false;
+
+ std::map<pid_t,std::vector<std::string>> debugMap; //will contain all used lsof files after filtering
+ Pathname _debugFile;
+ };
- if ( !t || !f || !n )
- return; // wrong filedescriptor/type/name
+ CheckAccessDeleted::Impl *CheckAccessDeleted::Impl::clone() const
+ {
+ Impl *myClone = new Impl( *this );
+ return myClone;
+ }
- if ( !( ( *t == 'R' && *(t+1) == 'E' && *(t+2) == 'G' && *(t+3) == '\0' )
- || ( *t == 'D' && *(t+1) == 'E' && *(t+2) == 'L' && *(t+3) == '\0' ) ) )
- return; // wrong type
+ /** Add \c cache to \c data if the process is accessing deleted files.
+ * \c pid string in \c cache is the proc line \c (pcuLR), \c files
+ * are already in place. Always clear the \c cache.files!
+ */
+ inline bool CheckAccessDeleted::Impl::addDataIf( const CacheEntry & cache_r, std::vector<std::string> *debMap )
+ {
+ const auto & filelist( cache_r.second );
- if ( !( ( *f == 'm' && *(f+1) == 'e' && *(f+2) == 'm' && *(f+3) == '\0' )
- || ( *f == 't' && *(f+1) == 'x' && *(f+2) == 't' && *(f+3) == '\0' )
- || ( *f == 'D' && *(f+1) == 'E' && *(f+2) == 'L' && *(f+3) == '\0' )
- || ( *f == 'l' && *(f+1) == 't' && *(f+2) == 'x' && *(f+3) == '\0' ) ) )
- return; // wrong filedescriptor type
+ if ( filelist.empty() )
+ return false;
- if ( str::contains( n, "(stat: Permission denied)" ) )
- return; // Avoid reporting false positive due to insufficient permission.
+ // at least one file access so keep it:
+ _data.push_back( CheckAccessDeleted::ProcInfo() );
+ CheckAccessDeleted::ProcInfo & pinfo( _data.back() );
+ pinfo.files.insert( pinfo.files.begin(), filelist.begin(), filelist.end() );
- if ( ! verbose_r )
+ const std::string & pline( cache_r.first );
+ std::string commandname; // pinfo.command if still needed...
+ std::ostringstream pLineStr; //rewrite the first line in debug cache
+ for_( ch, pline.begin(), pline.end() )
+ {
+ switch ( *ch )
{
- if ( ! ( str::contains( n, "/lib" ) || str::contains( n, "bin/" ) ) )
- return; // Try to avoid reporting false positive unless verbose.
+ case 'p':
+ pinfo.pid = &*(ch+1);
+ if ( debMap )
+ pLineStr <<&*(ch)<<'\0';
+ break;
+ case 'R':
+ pinfo.ppid = &*(ch+1);
+ if ( debMap )
+ pLineStr <<&*(ch)<<'\0';
+ break;
+ case 'u':
+ pinfo.puid = &*(ch+1);
+ if ( debMap )
+ pLineStr <<&*(ch)<<'\0';
+ break;
+ case 'L':
+ pinfo.login = &*(ch+1);
+ if ( debMap )
+ pLineStr <<&*(ch)<<'\0';
+ break;
+ case 'c':
+ if ( pinfo.command.empty() ) {
+ commandname = &*(ch+1);
+ // the lsof command name might be truncated, so we prefer /proc/<pid>/exe
+ if (!_fromLsofFileMode)
+ pinfo.command = filesystem::readlink( Pathname("/proc")/pinfo.pid/"exe" ).basename();
+ if ( pinfo.command.empty() )
+ pinfo.command = std::move(commandname);
+ if ( debMap )
+ pLineStr <<'c'<<pinfo.command<<'\0';
+ }
+ break;
}
+ if ( *ch == '\n' ) break; // end of data
+ do { ++ch; } while ( *ch != '\0' ); // skip to next field
+ }
+
+ //replace the data in the debug cache as well
+ if ( debMap ) {
+ pLineStr<<endl;
+ debMap->front() = pLineStr.str();
+ }
+
+ //entry was added
+ return true;
+ }
+
- if ( *f == 'm' || *f == 'D' ) // skip some wellknown nonlibrary memorymapped files
+ /** Add file to cache if it refers to a deleted executable or library file:
+ * - Either the link count \c(k) is \c 0, or no link cout is present.
+ * - The type \c (t) is set to \c REG or \c DEL
+ * - The filedescriptor \c (f) is set to \c txt, \c mem or \c DEL
+ */
+ inline void CheckAccessDeleted::Impl::addCacheIf( CacheEntry & cache_r, const std::string & line_r, std::vector<std::string> *debMap )
+ {
+ const char * f = 0;
+ const char * t = 0;
+ const char * n = 0;
+
+ for_( ch, line_r.c_str(), ch+line_r.size() )
+ {
+ switch ( *ch )
{
- static const char * black[] = {
- "/SYSV"
- , "/var/run/"
- , "/var/lib/sss/"
- , "/dev/"
- };
- for_( it, arrayBegin( black ), arrayEnd( black ) )
- {
- if ( str::hasPrefix( n, *it ) )
+ case 'k':
+ if ( *(ch+1) != '0' ) // skip non-zero link counts
return;
- }
+ break;
+ case 'f':
+ f = ch+1;
+ break;
+ case 't':
+ t = ch+1;
+ break;
+ case 'n':
+ n = ch+1;
+ break;
}
- // Add if no duplicate
- cache_r.second.insert( n );
+ if ( *ch == '\n' ) break; // end of data
+ do { ++ch; } while ( *ch != '\0' ); // skip to next field
}
- /////////////////////////////////////////////////////////////////
- /// \class FilterRunsInLXC
- /// \brief Functor guessing whether \a PID is running in a container.
- ///
- /// Assumme using different \c pid namespace than \c self.
- /////////////////////////////////////////////////////////////////
- struct FilterRunsInLXC
- {
- bool operator()( pid_t pid_r ) const
- { return( nsIno( pid_r, "pid" ) != pidNS ); }
+ if ( !t || !f || !n )
+ return; // wrong filedescriptor/type/name
- FilterRunsInLXC()
- : pidNS( nsIno( "self", "pid" ) )
- {}
+ if ( !( ( *t == 'R' && *(t+1) == 'E' && *(t+2) == 'G' && *(t+3) == '\0' )
+ || ( *t == 'D' && *(t+1) == 'E' && *(t+2) == 'L' && *(t+3) == '\0' ) ) )
+ return; // wrong type
- static inline ino_t nsIno( const std::string & pid_r, const std::string & ns_r )
- { return PathInfo("/proc/"+pid_r+"/ns/"+ns_r).ino(); }
+ if ( !( ( *f == 'm' && *(f+1) == 'e' && *(f+2) == 'm' && *(f+3) == '\0' )
+ || ( *f == 't' && *(f+1) == 'x' && *(f+2) == 't' && *(f+3) == '\0' )
+ || ( *f == 'D' && *(f+1) == 'E' && *(f+2) == 'L' && *(f+3) == '\0' )
+ || ( *f == 'l' && *(f+1) == 't' && *(f+2) == 'x' && *(f+3) == '\0' ) ) )
+ return; // wrong filedescriptor type
- static inline ino_t nsIno( pid_t pid_r, const std::string & ns_r )
- { return nsIno( asString(pid_r), ns_r ); }
+ if ( str::contains( n, "(stat: Permission denied)" ) )
+ return; // Avoid reporting false positive due to insufficient permission.
- ino_t pidNS;
- };
+ if ( ! _verbose )
+ {
+ if ( ! ( str::contains( n, "/lib" ) || str::contains( n, "bin/" ) ) )
+ return; // Try to avoid reporting false positive unless verbose.
+ }
-#if 0
- void lsofdebug( const Pathname & file_r )
+ if ( *f == 'm' || *f == 'D' ) // skip some wellknown nonlibrary memorymapped files
{
- std::ifstream infile( file_r.c_str() );
- USR << infile << endl;
- std::vector<std::string> fields;
- CacheEntry cache;
- for( iostr::EachLine in( infile ); in; in.next() )
+ static const char * black[] = {
+ "/SYSV"
+ , "/var/run/"
+ , "/var/lib/sss/"
+ , "/dev/"
+ , "/var/lib/gdm"
+ };
+ for_( it, arrayBegin( black ), arrayEnd( black ) )
{
- std::string field( *in );
- if ( field[0] == 'f' || field[0] == 'p' )
- {
- if ( !fields.empty() )
- {
- // consume
- std::string line( str::join( fields, "\n" ) );
- for ( char & c : line )
- { if ( c == '\n' ) c = '\0'; }
- line.push_back( '\n' );
-
- size_t sze = cache.second.size();
- addCacheIf( cache, line, false );
- if ( sze != cache.second.size() )
- USR << fields << endl;
-
- fields.clear();
- }
- if ( field[0] == 'p' )
- continue;
- fields.push_back( field );
- }
- else if ( !fields.empty() )
- {
- fields.push_back( field );
- }
+ if ( str::hasPrefix( n, *it ) )
+ return;
}
}
-#endif
- /////////////////////////////////////////////////////////////////
- } // namespace
- ///////////////////////////////////////////////////////////////////
+ // Add if no duplicate
+ if ( debMap && cache_r.second.find(n) == cache_r.second.end() ) {
+ debMap->push_back(line_r);
+ }
+ cache_r.second.insert( n );
+ }
- CheckAccessDeleted::size_type CheckAccessDeleted::check( bool verbose_r )
+ CheckAccessDeleted::CheckAccessDeleted( bool doCheck_r )
+ : _pimpl(new Impl)
{
- _data.clear();
+ if ( doCheck_r ) check();
+ }
- static const char* argv[] =
- {
- "lsof", "-n", "-FpcuLRftkn0", NULL
- };
- ExternalProgram prog( argv, ExternalProgram::Discard_Stderr );
+ CheckAccessDeleted::size_type CheckAccessDeleted::check( const Pathname &lsofOutput_r, bool verbose_r )
+ {
+ _pimpl->_verbose = verbose_r;
+ _pimpl->_fromLsofFileMode = true;
+
+ FILE *inFile = fopen( lsofOutput_r.c_str(), "r" );
+ if ( !inFile ) {
+ ZYPP_THROW( Exception( str::Format("Opening input file %1% failed.") % lsofOutput_r.c_str() ) );
+ }
+ //inFile is closed by ExternalDataSource
+ externalprogram::ExternalDataSource inSource( inFile, nullptr );
+ auto cache = _pimpl->filterInput( inSource );
+ return _pimpl->createProcInfo( cache );
+ }
+
+ std::map<pid_t,CacheEntry> CheckAccessDeleted::Impl::filterInput( externalprogram::ExternalDataSource &source )
+ {
// cachemap: PID => (deleted files)
// NOTE: omit PIDs running in a (lxc/docker) container
std::map<pid_t,CacheEntry> cachemap;
+
+ bool debugEnabled = !_debugFile.empty();
+
pid_t cachepid = 0;
FilterRunsInLXC runsInLXC;
- for( std::string line = prog.receiveLine(); ! line.empty(); line = prog.receiveLine() )
+ for( std::string line = source.receiveLine(); ! line.empty(); line = source.receiveLine() )
{
// NOTE: line contains '\0' separeated fields!
if ( line[0] == 'p' )
{
- str::strtonum( line.c_str()+1, cachepid ); // line is "p<PID>\0...."
- if ( !runsInLXC( cachepid ) )
- cachemap[cachepid].first.swap( line );
- else
- cachepid = 0; // ignore this pid
+ str::strtonum( line.c_str()+1, cachepid ); // line is "p<PID>\0...."
+ if ( _fromLsofFileMode || !runsInLXC( cachepid ) ) {
+ if ( debugEnabled ) {
+ auto &pidMad = debugMap[cachepid];
+ if ( pidMad.empty() )
+ debugMap[cachepid].push_back( line );
+ else
+ debugMap[cachepid].front() = line;
+ }
+ cachemap[cachepid].first.swap( line );
+ } else {
+ cachepid = 0; // ignore this pid
+ }
}
else if ( cachepid )
{
- addCacheIf( cachemap[cachepid], line, verbose_r );
+ auto &dbgMap = debugMap[cachepid];
+ addCacheIf( cachemap[cachepid], line, debugEnabled ? &dbgMap : nullptr);
}
}
+ return cachemap;
+ }
+
+ CheckAccessDeleted::size_type CheckAccessDeleted::check( bool verbose_r )
+ {
+ static const char* argv[] =
+ {
+ "lsof", "-n", "-FpcuLRftkn0", NULL
+ };
+
+ _pimpl->_verbose = verbose_r;
+ _pimpl->_fromLsofFileMode = false;
+
+ ExternalProgram prog( argv, ExternalProgram::Discard_Stderr );
+ std::map<pid_t,CacheEntry> cachemap = _pimpl->filterInput( prog );
int ret = prog.close();
if ( ret != 0 )
{
if ( ret == 129 )
{
- ZYPP_THROW( Exception(_("Please install package 'lsof' first.") ) );
+ ZYPP_THROW( Exception(_("Please install package 'lsof' first.") ) );
}
- Exception err( str::form("Executing 'lsof' failed (%d).", ret) );
+ Exception err( str::Format("Executing 'lsof' failed (%1%).") % ret );
err.remember( prog.execError() );
ZYPP_THROW( err );
}
- std::vector<ProcInfo> data;
- for ( const auto & cached : cachemap )
+ return _pimpl->createProcInfo( cachemap );
+ }
+
+ CheckAccessDeleted::size_type CheckAccessDeleted::Impl::createProcInfo(const std::map<pid_t,CacheEntry> &in)
+ {
+ std::ofstream debugFileOut;
+ bool debugEnabled = false;
+ if ( !_debugFile.empty() ) {
+ debugFileOut.open( _debugFile.c_str() );
+ debugEnabled = debugFileOut.is_open();
+
+ if ( !debugEnabled ) {
+ ERR<<"Unable to open debug file: "<<_debugFile<<endl;
+ }
+ }
+
+ _data.clear();
+ for ( const auto &cached : in )
{
- addDataIf( data, cached.second );
+ if (!debugEnabled)
+ addDataIf( cached.second);
+ else {
+ std::vector<std::string> *mapPtr = nullptr;
+
+ auto dbgInfo = debugMap.find(cached.first);
+ if ( dbgInfo != debugMap.end() )
+ mapPtr = &(dbgInfo->second);
+
+ if( !addDataIf( cached.second, mapPtr ) )
+ continue;
+
+ for ( const std::string &dbgLine: dbgInfo->second ) {
+ debugFileOut.write( dbgLine.c_str(), dbgLine.length() );
+ }
+ }
}
- _data.swap( data );
return _data.size();
}
+ bool CheckAccessDeleted::empty() const
+ {
+ return _pimpl->_data.empty();
+ }
+
+ CheckAccessDeleted::size_type CheckAccessDeleted::size() const
+ {
+ return _pimpl->_data.size();
+ }
+
+ CheckAccessDeleted::const_iterator CheckAccessDeleted::begin() const
+ {
+ return _pimpl->_data.begin();
+ }
+
+ CheckAccessDeleted::const_iterator CheckAccessDeleted::end() const
+ {
+ return _pimpl->_data.end();
+ }
+
+ void CheckAccessDeleted::setDebugOutputFile(const Pathname &filename_r)
+ {
+ _pimpl->_debugFile = filename_r;
+ }
+
std::string CheckAccessDeleted::findService( pid_t pid_r )
{
ProcInfo p;
return p.service();
}
- ///////////////////////////////////////////////////////////////////
- namespace
- { /////////////////////////////////////////////////////////////////
- /////////////////////////////////////////////////////////////////
- } // namespace
- ///////////////////////////////////////////////////////////////////
-
std::string CheckAccessDeleted::ProcInfo::service() const
{
static const str::regex rx( "[0-9]+:name=systemd:/system.slice/(.*/)?(.*).service$" );
#include <iosfwd>
#include <vector>
#include <string>
+#include <zypp/Pathname.h>
+#include <zypp/base/PtrTypes.h>
///////////////////////////////////////////////////////////////////
namespace zypp
* information about running processes which access deleted files
* or libraries is collected and provided as a \ref ProcInfo
* container.
+ *
+ * Provides support for reproducing check results from a foreign system by
+ * creating a debug output file containing all required information,
+ * enabled by \ref setDebugOutputFile.\n
+ * This data file can be used as datasource when passed to \ref check(const Pathname &, bool).
*/
class CheckAccessDeleted
{
public:
+ class Impl;
/**
* Data about one running process accessing deleted files.
*/
* \throws Exception if \ref check throws.
* \see \ref check.
*/
- CheckAccessDeleted( bool doCheck_r = true )
- { if ( doCheck_r ) check(); }
+ CheckAccessDeleted( bool doCheck_r = true );
public:
/** Check for running processes which access deleted executables or libraries.
*/
size_type check( bool verbose_r = false );
- bool empty() const { return _data.empty(); }
- size_type size() const { return _data.size(); }
- const_iterator begin() const { return _data.begin(); }
- const_iterator end() const { return _data.end(); }
+ /**
+ * \overload
+ * Performs the same checks but instead of investigating the current system it
+ * uses information from \a lsofOutput_r to support debugging.
+ *
+ * \sa setDebugOutputFile
+ */
+ size_type check( const Pathname &lsofOutput_r, bool verbose_r = false );
+
+ bool empty() const;
+ size_type size() const;
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ /**
+ * Writes all filtered process entries that make it into the final set into
+ * a file specified by \a filename_r.
+ */
+ void setDebugOutputFile (const Pathname &filename_r);
public:
/** Guess if pid was started by a systemd service script.
* \warning This is just a guess.
*/
static std::string findService( pid_t pid_r );
-
- private:
- std::vector<ProcInfo> _data;
+ private:
+ RWCOW_pointer<Impl> _pimpl;
};
///////////////////////////////////////////////////////////////////