From 4ca9365ce360cfe9e2a916b1cb70a69b409c26cd Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Thu, 13 Aug 2015 15:29:03 +0200 Subject: [PATCH 01/16] Change MessageID and PeerID type to UIDs [Feature] MessageID and PeerID are generated with UIDs - a timestamp and UUID pair. [Cause] Previously used unsigned ints might overflow and create a security issue. [Solution] Implement UID class, change MessageID and PeerID to use UID [Verification] Build, install, run tests Change-Id: I493cba8e55cc9985d3b2b544b78c434d4deb4191 --- common/api/ipc-method-result-builder.cpp | 2 +- libs/ipc/CMakeLists.txt | 2 +- libs/ipc/client.cpp | 2 +- libs/ipc/internals/processor.cpp | 48 ++++++++-------- libs/ipc/internals/processor.hpp | 11 ++++ libs/ipc/types.cpp | 24 ++++++-- libs/ipc/types.hpp | 4 +- libs/ipc/unique-id.cpp | 64 +++++++++++++++++++++ libs/ipc/unique-id.hpp | 97 ++++++++++++++++++++++++++++++++ packaging/vasum.spec | 2 + server/host-ipc-connection.cpp | 2 +- tests/unit_tests/ipc/ut-ipc.cpp | 3 +- tests/unit_tests/ipc/ut-unique-id.cpp | 73 ++++++++++++++++++++++++ 13 files changed, 300 insertions(+), 34 deletions(-) create mode 100644 libs/ipc/unique-id.cpp create mode 100644 libs/ipc/unique-id.hpp create mode 100644 tests/unit_tests/ipc/ut-unique-id.cpp diff --git a/common/api/ipc-method-result-builder.cpp b/common/api/ipc-method-result-builder.cpp index d7ac681..5d7e2c4 100644 --- a/common/api/ipc-method-result-builder.cpp +++ b/common/api/ipc-method-result-builder.cpp @@ -50,7 +50,7 @@ void IPCMethodResultBuilder::setError(const std::string& , const std::string& me std::string IPCMethodResultBuilder::getID() const { - return IPC_CONNECTION_PREFIX + std::to_string(mMethodResultPtr->getPeerID()); + return IPC_CONNECTION_PREFIX + mMethodResultPtr->getPeerID(); } } // namespace result diff --git a/libs/ipc/CMakeLists.txt b/libs/ipc/CMakeLists.txt index 2fce8cb..854e0de 100644 --- a/libs/ipc/CMakeLists.txt +++ b/libs/ipc/CMakeLists.txt @@ -50,7 +50,7 @@ SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES ## Link libraries ############################################################## IF(NOT WITHOUT_SYSTEMD) -PKG_CHECK_MODULES(IPC_DEPS REQUIRED libsystemd-daemon) +PKG_CHECK_MODULES(IPC_DEPS REQUIRED libsystemd-daemon uuid) ENDIF(NOT WITHOUT_SYSTEMD) INCLUDE_DIRECTORIES(${LIBS_FOLDER}) diff --git a/libs/ipc/client.cpp b/libs/ipc/client.cpp index 245faee..c5105f9 100644 --- a/libs/ipc/client.cpp +++ b/libs/ipc/client.cpp @@ -32,7 +32,7 @@ namespace ipc { Client::Client(epoll::EventPoll& eventPoll, const std::string& socketPath) : mEventPoll(eventPoll), - mServiceID(-1), + mServiceID(), mProcessor(eventPoll, "[CLIENT] "), mSocketPath(socketPath) { diff --git a/libs/ipc/internals/processor.cpp b/libs/ipc/internals/processor.cpp index a8c671e..fdbcbe8 100644 --- a/libs/ipc/internals/processor.cpp +++ b/libs/ipc/internals/processor.cpp @@ -26,7 +26,8 @@ #include "ipc/exception.hpp" #include "ipc/internals/processor.hpp" -#include "utils/exception.hpp" +#include "config/manager.hpp" +#include "config/exception.hpp" #include #include @@ -290,39 +291,36 @@ bool Processor::handleInput(const FileDescriptor fd) return false; } - - MethodID methodID; - MessageID messageID; + MessageHeader hdr; { try { // Read information about the incoming data Socket& socket = *peerIt->socketPtr; Socket::Guard guard = socket.getGuard(); - socket.read(&methodID, sizeof(methodID)); - socket.read(&messageID, sizeof(messageID)); - } catch (const UtilsException& e) { + config::loadFromFD(socket.getFD(), hdr); + } catch (const config::ConfigException& e) { LOGE(mLogPrefix + "Error during reading the socket"); removePeerInternal(peerIt, std::make_exception_ptr(IPCNaughtyPeerException())); return true; } - if (methodID == RETURN_METHOD_ID) { - return onReturnValue(peerIt, messageID); + if (hdr.methodID == RETURN_METHOD_ID) { + return onReturnValue(peerIt, hdr.messageID); } else { - if (mMethodsCallbacks.count(methodID)) { + if (mMethodsCallbacks.count(hdr.methodID)) { // Method - std::shared_ptr methodCallbacks = mMethodsCallbacks.at(methodID); - return onRemoteMethod(peerIt, methodID, messageID, methodCallbacks); + std::shared_ptr methodCallbacks = mMethodsCallbacks.at(hdr.methodID); + return onRemoteMethod(peerIt, hdr.methodID, hdr.messageID, methodCallbacks); - } else if (mSignalsCallbacks.count(methodID)) { + } else if (mSignalsCallbacks.count(hdr.methodID)) { // Signal - std::shared_ptr signalCallbacks = mSignalsCallbacks.at(methodID); - return onRemoteSignal(peerIt, methodID, messageID, signalCallbacks); + std::shared_ptr signalCallbacks = mSignalsCallbacks.at(hdr.methodID); + return onRemoteSignal(peerIt, hdr.methodID, hdr.messageID, signalCallbacks); } else { - LOGW(mLogPrefix + "No method or signal callback for methodID: " << methodID); + LOGW(mLogPrefix + "No method or signal callback for methodID: " << hdr.methodID); removePeerInternal(peerIt, std::make_exception_ptr(IPCNaughtyPeerException())); return true; @@ -503,12 +501,14 @@ bool Processor::onMethodRequest(MethodRequest& request) std::move(request.parse), std::move(request.process))); + MessageHeader hdr; try { // Send the call with the socket Socket& socket = *peerIt->socketPtr; Socket::Guard guard = socket.getGuard(); - socket.write(&request.methodID, sizeof(request.methodID)); - socket.write(&request.messageID, sizeof(request.messageID)); + hdr.methodID = request.methodID; + hdr.messageID = request.messageID; + config::saveToFD(socket.getFD(), hdr); LOGT(mLogPrefix + "Serializing the message"); request.serialize(socket.getFD(), request.data); } catch (const std::exception& e) { @@ -540,12 +540,14 @@ bool Processor::onSignalRequest(SignalRequest& request) return false; } + MessageHeader hdr; try { // Send the call with the socket Socket& socket = *peerIt->socketPtr; Socket::Guard guard = socket.getGuard(); - socket.write(&request.methodID, sizeof(request.methodID)); - socket.write(&request.messageID, sizeof(request.messageID)); + hdr.methodID = request.methodID; + hdr.messageID = request.messageID; + config::saveToFD(socket.getFD(), hdr); request.serialize(socket.getFD(), request.data); } catch (const std::exception& e) { LOGE(mLogPrefix + "Error during sending a signal: " << e.what()); @@ -627,12 +629,14 @@ bool Processor::onSendResultRequest(SendResultRequest& request) return true; } + MessageHeader hdr; try { // Send the call with the socket Socket& socket = *peerIt->socketPtr; Socket::Guard guard = socket.getGuard(); - socket.write(&RETURN_METHOD_ID, sizeof(RETURN_METHOD_ID)); - socket.write(&request.messageID, sizeof(request.messageID)); + hdr.methodID = RETURN_METHOD_ID; + hdr.messageID = request.messageID; + config::saveToFD(socket.getFD(), hdr); LOGT(mLogPrefix + "Serializing the message"); methodCallbacks->serialize(socket.getFD(), request.data); } catch (const std::exception& e) { diff --git a/libs/ipc/internals/processor.hpp b/libs/ipc/internals/processor.hpp index 7f7cd63..2706792 100644 --- a/libs/ipc/internals/processor.hpp +++ b/libs/ipc/internals/processor.hpp @@ -336,6 +336,17 @@ private: CONFIG_REGISTER_EMPTY }; + struct MessageHeader { + MethodID methodID; + MessageID messageID; + + CONFIG_REGISTER + ( + methodID, + messageID + ) + }; + struct RegisterSignalsProtocolMessage { RegisterSignalsProtocolMessage() = default; RegisterSignalsProtocolMessage(const std::vector& ids) diff --git a/libs/ipc/types.cpp b/libs/ipc/types.cpp index 0961b35..6098cb4 100644 --- a/libs/ipc/types.cpp +++ b/libs/ipc/types.cpp @@ -25,25 +25,39 @@ #include "config.hpp" #include "ipc/types.hpp" +#include "ipc/unique-id.hpp" #include "logger/logger.hpp" -#include +#include namespace ipc { namespace { -std::atomic gLastMessageID(0); -std::atomic gLastPeerID(0); +// complex types cannot be easily used with std::atomic - these require libatomic to be linked +// instead, secure the ID getters with mutex +MessageID gLastMessageID; +PeerID gLastPeerID; + +std::mutex gMessageIDMutex; +std::mutex gPeerIDMutex; } // namespace MessageID getNextMessageID() { - return ++gLastMessageID; + std::unique_lock lock(gMessageIDMutex); + UniqueID uid; + uid.generate(); + gLastMessageID = uid; + return gLastMessageID; } PeerID getNextPeerID() { - return ++gLastPeerID; + std::unique_lock lock(gPeerIDMutex); + UniqueID uid; + uid.generate(); + gLastPeerID = uid; + return gLastPeerID; } diff --git a/libs/ipc/types.hpp b/libs/ipc/types.hpp index ab4ed00..fad01b3 100644 --- a/libs/ipc/types.hpp +++ b/libs/ipc/types.hpp @@ -33,8 +33,8 @@ namespace ipc { typedef int FileDescriptor; typedef unsigned int MethodID; -typedef unsigned int MessageID; -typedef unsigned int PeerID; +typedef std::string MessageID; +typedef std::string PeerID; typedef std::function PeerCallback; typedef std::function& data)> SerializeCallback; diff --git a/libs/ipc/unique-id.cpp b/libs/ipc/unique-id.cpp new file mode 100644 index 0000000..bcdd4bc --- /dev/null +++ b/libs/ipc/unique-id.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Kostyra + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @brief Unique ID type definition + */ + +#include "unique-id.hpp" + +namespace ipc { + +UniqueID::UniqueID() +{ + mTime.tv_sec = 0; + mTime.tv_nsec = 0; + ::uuid_clear(mUUID); +} + +void UniqueID::generate() +{ + ::clock_gettime(CLOCK_REALTIME, &mTime); + ::uuid_generate_random(mUUID); +} + +bool UniqueID::operator==(const UniqueID& other) const +{ + return (mTime.tv_sec == other.mTime.tv_sec) + && (mTime.tv_nsec == other.mTime.tv_nsec) + && (::uuid_compare(mUUID, other.mUUID) == 0); // uuid_compare works just like strcmp +} + +UniqueID::operator std::string() const +{ + char uuid[37]; // uuid_unparse assures that it will print 36 chars + terminating zero + ::uuid_unparse(mUUID, uuid); + return std::to_string(mTime.tv_sec) + '.' + std::to_string(mTime.tv_nsec) + ':' + uuid; +} + +std::ostream& operator<<(std::ostream& str, const UniqueID& id) +{ + char uuid[37]; + ::uuid_unparse(id.mUUID, uuid); + str << id.mTime.tv_sec << "." << id.mTime.tv_nsec << ":" << uuid; + return str; +} + +} // namespace ipc diff --git a/libs/ipc/unique-id.hpp b/libs/ipc/unique-id.hpp new file mode 100644 index 0000000..bceda62 --- /dev/null +++ b/libs/ipc/unique-id.hpp @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Kostyra + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @brief Unique ID type declaration + */ + +#ifndef IPC_UNIQUE_ID_HPP +#define IPC_UNIQUE_ID_HPP + +#include +#include +#include +#include + +namespace ipc { + +class UniqueID { +public: + typedef struct timespec TimestampType; + typedef uuid_t UUIDType; + + /** + * Default constructor. Generates an empty ID. + */ + UniqueID(); + + /** + * Generate new timestamp and UUID pair. + */ + void generate(); + + /** + * Compare two IDs + * + * @param other Other ID to compare to. + * @return True if both timestamp and UUID are equal, false otherwise. + */ + bool operator==(const UniqueID& other) const; + + /** + * Casts current ID to string + */ + operator std::string() const; + + /** + * Overloaded << operator for debugging purposes. Used in ut-uid.cpp tests. + */ + friend std::ostream& operator<<(std::ostream& str, const UniqueID& id); + + + TimestampType mTime; //< timestamp when generate() was called + UUIDType mUUID; //< random UUID generated with libuuid +}; + +template +class hash; + +template <> +class hash +{ +public: + std::size_t operator()(const ipc::UniqueID& id) const + { + char uuid[37]; // 36 chars for UUID + terminating zero + ::uuid_unparse(id.mUUID, uuid); + + // STL does not provide correct hash implementation for char * + // Instead, just convert it to string + std::string uuids(uuid); + + return std::hash()(id.mTime.tv_sec) + ^ std::hash()(id.mTime.tv_nsec) + ^ std::hash()(uuids); + } +}; + +} // namespace ipc + +#endif // IPC_UNIQUE_ID_HPP diff --git a/packaging/vasum.spec b/packaging/vasum.spec index 22de326..2cd5dd8 100644 --- a/packaging/vasum.spec +++ b/packaging/vasum.spec @@ -437,6 +437,8 @@ The package provides libConfig development tools and libs. Summary: IPC library Group: Security/Other Requires: libConfig +Requires: libuuid +BuildRequires: libuuid-devel Requires(post): /sbin/ldconfig Requires(postun): /sbin/ldconfig diff --git a/server/host-ipc-connection.cpp b/server/host-ipc-connection.cpp index c2ba755..a575c70 100644 --- a/server/host-ipc-connection.cpp +++ b/server/host-ipc-connection.cpp @@ -42,7 +42,7 @@ HostIPCConnection::HostIPCConnection(ipc::epoll::EventPoll& eventPoll, ZonesMana ipc::PeerCallback removedCallback = [this](const ipc::PeerID peerID, const ipc::FileDescriptor) { - std::string id = api::IPC_CONNECTION_PREFIX + std::to_string(peerID); + std::string id = api::IPC_CONNECTION_PREFIX + peerID; mZonesManagerPtr->disconnectedCallback(id); }; mService.reset(new ipc::Service(eventPoll, HOST_IPC_SOCKET, diff --git a/tests/unit_tests/ipc/ut-ipc.cpp b/tests/unit_tests/ipc/ut-ipc.cpp index 8bb829e..853faa2 100644 --- a/tests/unit_tests/ipc/ut-ipc.cpp +++ b/tests/unit_tests/ipc/ut-ipc.cpp @@ -33,6 +33,7 @@ #include "ipc/service.hpp" #include "ipc/client.hpp" #include "ipc/types.hpp" +#include "ipc/unique-id.hpp" #include "ipc/result.hpp" #include "ipc/epoll/thread-dispatcher.hpp" #include "ipc/epoll/glib-dispatcher.hpp" @@ -224,7 +225,7 @@ PeerID connect(Service& s, Client& c) PeerID peerID = peerIDLatch.get(TIMEOUT); s.setNewPeerCallback(nullptr); - BOOST_REQUIRE_NE(peerID, 0); + BOOST_REQUIRE_NE(peerID, static_cast(ipc::UniqueID())); return peerID; } diff --git a/tests/unit_tests/ipc/ut-unique-id.cpp b/tests/unit_tests/ipc/ut-unique-id.cpp new file mode 100644 index 0000000..05ce1bb --- /dev/null +++ b/tests/unit_tests/ipc/ut-unique-id.cpp @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Kostyra + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + + +/** + * @file + * @author Lukasz Kostyra (l.kostyra@samsung.com) + * @brief Unit tests of UID + */ + +#include "config.hpp" +#include "ut.hpp" + +#include "ipc/unique-id.hpp" + +#include +#include + +namespace { + +const std::string EMPTY_UUID = "00000000-0000-0000-0000-000000000000"; + +} // namespace + +BOOST_AUTO_TEST_SUITE(UniqueIDSuite) + +// constructor should provide empty timestamp and UUID +BOOST_AUTO_TEST_CASE(Constructor) +{ + ipc::UniqueID uid; + + BOOST_CHECK_EQUAL(static_cast(uid.mTime.tv_sec), 0); + BOOST_CHECK_EQUAL(uid.mTime.tv_nsec, 0); + char uuid[37]; // 36 chars + terminating zero + ::uuid_unparse(uid.mUUID, uuid); + BOOST_CHECK(EMPTY_UUID.compare(uuid) == 0); +} + +// generate one UID and compare with empty +BOOST_AUTO_TEST_CASE(Generate) +{ + ipc::UniqueID uid, emptyuid; + uid.generate(); + + BOOST_CHECK_NE(uid, emptyuid); +} + +// generate two UIDs and compare them +BOOST_AUTO_TEST_CASE(DoubleGenerate) +{ + ipc::UniqueID uid1, uid2; + + uid1.generate(); + uid2.generate(); + BOOST_CHECK_NE(uid1, uid2); +} + +BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 42745f132f330133017084e7d10749a7ccbf48e3 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Thu, 27 Aug 2015 17:06:30 +0200 Subject: [PATCH 02/16] lxcpp: Setting up environment variables [Feature] Setting up environement in attach Created the commands directory [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I7526f04ca48e931be75a99cdbf774b4c5fbb5c35 --- libs/lxcpp/CMakeLists.txt | 17 ++-- libs/lxcpp/{ => commands}/attach-manager.cpp | 65 +++++++++---- libs/lxcpp/{ => commands}/attach-manager.hpp | 20 +++- libs/lxcpp/container-impl.cpp | 15 ++- libs/lxcpp/container.hpp | 2 +- libs/lxcpp/environment.cpp | 92 ++++++++++++++++++ libs/lxcpp/environment.hpp | 52 ++++++++++ libs/lxcpp/exception.hpp | 10 ++ tests/unit_tests/lxcpp/ut-environment.cpp | 140 +++++++++++++++++++++++++++ 9 files changed, 378 insertions(+), 35 deletions(-) rename libs/lxcpp/{ => commands}/attach-manager.cpp (66%) rename libs/lxcpp/{ => commands}/attach-manager.hpp (64%) create mode 100644 libs/lxcpp/environment.cpp create mode 100644 libs/lxcpp/environment.hpp create mode 100644 tests/unit_tests/lxcpp/ut-environment.cpp diff --git a/libs/lxcpp/CMakeLists.txt b/libs/lxcpp/CMakeLists.txt index b04e437..c76de74 100644 --- a/libs/lxcpp/CMakeLists.txt +++ b/libs/lxcpp/CMakeLists.txt @@ -22,12 +22,14 @@ PROJECT(lxcpp) MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the liblxcpp...") FILE(GLOB HEADERS *.hpp) -FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/fd-utils.hpp - ${COMMON_FOLDER}/utils/exception.hpp - ${COMMON_FOLDER}/utils/channel.hpp - ${COMMON_FOLDER}/utils/environment.hpp - ${COMMON_FOLDER}/utils/execute.hpp) +FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/fd-utils.hpp + ${COMMON_FOLDER}/utils/exception.hpp + ${COMMON_FOLDER}/utils/channel.hpp + ${COMMON_FOLDER}/utils/environment.hpp + ${COMMON_FOLDER}/utils/execute.hpp) FILE(GLOB HEADERS_NETLINK ${COMMON_FOLDER}/netlink/*.hpp) +FILE(GLOB HEADERS_COMMANDS commands/*.hpp) + FILE(GLOB SRCS *.cpp *.hpp) FILE(GLOB SRCS_UTILS ${COMMON_FOLDER}/utils/fd-utils.cpp ${COMMON_FOLDER}/utils/exception.cpp @@ -35,13 +37,14 @@ FILE(GLOB SRCS_UTILS ${COMMON_FOLDER}/utils/fd-utils.cpp ${COMMON_FOLDER}/utils/environment.cpp ${COMMON_FOLDER}/utils/execute.cpp) FILE(GLOB SRCS_NETLINK ${COMMON_FOLDER}/netlink/*.cpp) +FILE(GLOB SRCS_COMMANDS commands/*.cpp) SET(_LIB_VERSION_ "${VERSION}") SET(_LIB_SOVERSION_ "0") SET(PC_FILE "lib${PROJECT_NAME}.pc") ## Setup target ################################################################ -ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_UTILS} ${SRCS_NETLINK}) +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_UTILS} ${SRCS_NETLINK} ${SRCS_COMMANDS}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${_LIB_SOVERSION_} VERSION ${_LIB_VERSION_} @@ -70,3 +73,5 @@ INSTALL(FILES ${HEADERS_UTILS} DESTINATION ${INCLUDE_INSTALL_DIR}/lxcpp/utils) INSTALL(FILES ${HEADERS_NETLINK} DESTINATION ${INCLUDE_INSTALL_DIR}/lxcpp/netlink) +INSTALL(FILES ${HEADERS_COMMANDS} + DESTINATION ${INCLUDE_INSTALL_DIR}/lxcpp/commands) diff --git a/libs/lxcpp/attach-manager.cpp b/libs/lxcpp/commands/attach-manager.cpp similarity index 66% rename from libs/lxcpp/attach-manager.cpp rename to libs/lxcpp/commands/attach-manager.cpp index 3479673..1a274d3 100644 --- a/libs/lxcpp/attach-manager.cpp +++ b/libs/lxcpp/commands/attach-manager.cpp @@ -21,18 +21,20 @@ * @brief Implementation of attaching to a container */ -#include "lxcpp/attach-manager.hpp" +#include "lxcpp/commands/attach-manager.hpp" #include "lxcpp/exception.hpp" #include "lxcpp/process.hpp" #include "lxcpp/filesystem.hpp" #include "lxcpp/namespace.hpp" #include "lxcpp/capability.hpp" +#include "lxcpp/environment.hpp" #include "utils/exception.hpp" #include #include +#include namespace lxcpp { @@ -64,6 +66,16 @@ void setupMountPoints() */ } +int execFunction(void* call) +{ + try { + return (*static_cast(call))(); + } catch(...) { + return -1; // Non-zero on failure + } + return 0; // Success +} + } // namespace AttachManager::AttachManager(lxcpp::ContainerImpl& container) @@ -75,12 +87,21 @@ AttachManager::~AttachManager() { } -void AttachManager::attach(Container::AttachCall& call, - const std::string& wdInContainer) +void AttachManager::attach(Container::AttachCall& userCall, + const int capsToKeep, + const std::string& workDirInContainer, + const std::vector& envToKeep, + const std::vector>& envToSet) { // Channels for setup synchronization utils::Channel intermChannel; + Call call = std::bind(&AttachManager::child, + std::move(userCall), + capsToKeep, + std::move(envToKeep), + std::move(envToSet)); + const pid_t interPid = lxcpp::fork(); if (interPid > 0) { intermChannel.setLeft(); @@ -88,23 +109,29 @@ void AttachManager::attach(Container::AttachCall& call, intermChannel.shutdown(); } else { intermChannel.setRight(); - interm(intermChannel, wdInContainer, call); + interm(intermChannel, workDirInContainer, call); intermChannel.shutdown(); ::_exit(0); } } -int AttachManager::child(void* data) +int AttachManager::child(const Container::AttachCall& call, + const int capsToKeep, + const std::vector& envToKeep, + const std::vector>& envToSet) { - try { - // TODO Pass mask and options via data - dropCapsFromBoundingExcept(0); - setupMountPoints(); - return (*static_cast(data))(); - } catch(...) { - return -1; // Non-zero on failure - } - return 0; // Success + // Setup capabilities + dropCapsFromBoundingExcept(capsToKeep); + + // Setup /proc /sys mount + setupMountPoints(); + + // Setup environment variables + clearenvExcept(envToKeep); + setenv(envToSet); + + // Run user's code + return call(); } void AttachManager::parent(utils::Channel& intermChannel, const pid_t interPid) @@ -118,18 +145,18 @@ void AttachManager::parent(utils::Channel& intermChannel, const pid_t interPid) } void AttachManager::interm(utils::Channel& intermChannel, - const std::string& wdInContainer, - Container::AttachCall& call) + const std::string& workDirInContainer, + Call& call) { lxcpp::setns(mContainer.getInitPid(), mContainer.getNamespaces()); // Change the current work directory - // wdInContainer is a path relative to the container's root - lxcpp::chdir(wdInContainer); + // workDirInContainer is a path relative to the container's root + lxcpp::chdir(workDirInContainer); // PID namespace won't affect the returned pid // CLONE_PARENT: Child's PPID == Caller's PID - const pid_t childPid = lxcpp::clone(&AttachManager::child, + const pid_t childPid = lxcpp::clone(execFunction, &call, CLONE_PARENT); intermChannel.write(childPid); diff --git a/libs/lxcpp/attach-manager.hpp b/libs/lxcpp/commands/attach-manager.hpp similarity index 64% rename from libs/lxcpp/attach-manager.hpp rename to libs/lxcpp/commands/attach-manager.hpp index be37ade..f286564 100644 --- a/libs/lxcpp/attach-manager.hpp +++ b/libs/lxcpp/commands/attach-manager.hpp @@ -33,6 +33,8 @@ namespace lxcpp { class AttachManager final { public: + typedef std::function Call; + AttachManager(lxcpp::ContainerImpl& container); ~AttachManager(); @@ -40,22 +42,32 @@ public: * Runs the call in the container's context * * @param call function to run inside container - * @param wdInContainer Current Work Directory. Path relative to container's root + * @param capsToKeep mask of the capabilities that shouldn't be dropped + * @param workDirInContainer Current Work Directory. Path relative to container's root + * @param envToKeep environment variables to keep in container + * @param envToSet environment variables to add/modify in container */ void attach(Container::AttachCall& call, - const std::string& wdInContainer); + const int capsToKeep, + const std::string& workDirInContainer, + const std::vector& envToKeep, + const std::vector>& envToSet); private: + const lxcpp::ContainerImpl& mContainer; // Methods for different stages of setting up the attachment - static int child(void* data); + static int child(const Container::AttachCall& call, + const int capsToKeep, + const std::vector& envToKeep, + const std::vector>& envToSet); void parent(utils::Channel& intermChannel, const pid_t pid); void interm(utils::Channel& intermChannel, - const std::string& wdInContainer, + const std::string& workDirInContainer, Container::AttachCall& call); }; diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp index 6de22dc..0d8d5b1 100644 --- a/libs/lxcpp/container-impl.cpp +++ b/libs/lxcpp/container-impl.cpp @@ -27,7 +27,7 @@ #include "lxcpp/filesystem.hpp" #include "lxcpp/namespace.hpp" #include "lxcpp/capability.hpp" -#include "lxcpp/attach-manager.hpp" +#include "lxcpp/commands/attach-manager.hpp" #include "utils/exception.hpp" @@ -108,7 +108,12 @@ void ContainerImpl::attach(Container::AttachCall& call, const std::string& cwdInContainer) { AttachManager attachManager(*this); - attachManager.attach(call, cwdInContainer); + // TODO: Env variables should agree with the ones already in the container + attachManager.attach(call, + /*capsToKeep*/ 0, + cwdInContainer, + /*envToKeep*/ {}, + /*envInContainer*/{{"container","lxcpp"}} ); } const std::vector& ContainerImpl::getNamespaces() const @@ -141,9 +146,9 @@ NetworkInterfaceInfo ContainerImpl::getInterfaceInfo(const std::string& /*ifname } void ContainerImpl::createInterface(const std::string& hostif, - const std::string& zoneif, - InterfaceType type, - MacVLanMode mode) + const std::string& zoneif, + InterfaceType type, + MacVLanMode mode) { NetworkInterface ni(*this, zoneif); ni.create(hostif, type, mode); diff --git a/libs/lxcpp/container.hpp b/libs/lxcpp/container.hpp index d07bc27..882aa87 100644 --- a/libs/lxcpp/container.hpp +++ b/libs/lxcpp/container.hpp @@ -46,7 +46,7 @@ struct NetworkInterfaceInfo { class Container { public: - typedef std::function AttachCall; + typedef std::function AttachCall; virtual ~Container() {}; diff --git a/libs/lxcpp/environment.cpp b/libs/lxcpp/environment.cpp new file mode 100644 index 0000000..489608b --- /dev/null +++ b/libs/lxcpp/environment.cpp @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Handling environment variables + */ + +#include "lxcpp/environment.hpp" +#include "lxcpp/exception.hpp" + +#include "logger/logger.hpp" +#include "utils/exception.hpp" + +#include + +namespace lxcpp { + +void clearenvExcept(const std::vector& names) +{ + // Backup keeps pairs (name,value) + std::vector> backup; + for(const auto& name: names) { + try { + backup.push_back({name, lxcpp::getenv(name)}); + } catch(const NoSuchValue&) { + // Continue if there's no such variable + } + } + + lxcpp::clearenv(); + + // Restore backup + lxcpp::setenv(backup); +} + +void clearenv() +{ + if(::clearenv()) { + const std::string msg = "clearenv() failed: " + + utils::getSystemErrorMessage(); + LOGE(msg); + throw EnvironmentSetupException(msg); + } +} + +std::string getenv(const std::string& name) +{ + const char* value = ::getenv(name.c_str()); + if (!value) { + const std::string msg = "getenv() failed: No such name"; + LOGW(msg); + throw NoSuchValue(msg); + } + return value; +} + +void setenv(const std::string& name, const std::string& value) +{ + if (-1 == ::setenv(name.c_str(), + value.c_str(), + 1 /*write if exists*/)) { + const std::string msg = "setenv() failed. Not all env set. " + + utils::getSystemErrorMessage(); + LOGE(msg); + throw EnvironmentSetupException(msg); + } +} + +void setenv(const std::vector>& variables) +{ + for(const auto& variable: variables) { + lxcpp::setenv(variable.first, variable.second); + } +} + +} // namespace lxcpp diff --git a/libs/lxcpp/environment.hpp b/libs/lxcpp/environment.hpp new file mode 100644 index 0000000..c9d8a20 --- /dev/null +++ b/libs/lxcpp/environment.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Handling environment variables + */ + +#ifndef LXCPP_ENVIRONMENT_HPP +#define LXCPP_ENVIRONMENT_HPP + +#include +#include +#include + +namespace lxcpp { + +void clearenv(); + +/** + * Clears the env variables except those listed. + * There's a race condition - a moment when listed variables aren't set + * Function should be used only for setting up a new process. + * + * @param names names of the variables to keep + */ +void clearenvExcept(const std::vector& names); + +std::string getenv(const std::string& name); + +void setenv(const std::string& name, const std::string& value); + +void setenv(const std::vector>& variables); + +} // namespace lxcpp + +#endif // LXCPP_ENVIRONMENT_HPP diff --git a/libs/lxcpp/exception.hpp b/libs/lxcpp/exception.hpp index 51dc5ec..8c11131 100644 --- a/libs/lxcpp/exception.hpp +++ b/libs/lxcpp/exception.hpp @@ -51,6 +51,11 @@ struct FileSystemSetupException: public Exception { : Exception(message) {} }; +struct EnvironmentSetupException: public Exception { + EnvironmentSetupException(const std::string& message = "Error during handling environment variables") + : Exception(message) {} +}; + struct CapabilitySetupException: public Exception { CapabilitySetupException(const std::string& message = "Error during a capability operation") : Exception(message) {} @@ -61,6 +66,11 @@ struct BadArgument: public Exception { : Exception(message) {} }; +struct NoSuchValue: public Exception { + NoSuchValue(const std::string& message = "Value not found") + : Exception(message) {} +}; + struct NetworkException : public Exception { NetworkException (const std::string& message = "Error during setting up a network") : Exception(message) {} diff --git a/tests/unit_tests/lxcpp/ut-environment.cpp b/tests/unit_tests/lxcpp/ut-environment.cpp new file mode 100644 index 0000000..8d6d45d --- /dev/null +++ b/tests/unit_tests/lxcpp/ut-environment.cpp @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jan Olszak(j.olszak@samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + + +/** + * @file + * @author Jan Olszak(j.olszak@samsung.com) + * @brief Unit tests of lxcpp namespace helpers + */ + +#include "config.hpp" +#include "ut.hpp" + +#include "lxcpp/environment.hpp" +#include "lxcpp/exception.hpp" +#include "lxcpp/namespace.hpp" +#include "lxcpp/process.hpp" + +#include "utils/execute.hpp" + +#include +#include +#include + +namespace { + +struct Fixture { + Fixture() {} + ~Fixture() {} +}; + +const int TEST_PASSED = 0; +const int ERROR = 1; + +const std::string TEST_NAME = "TEST_NAME"; +const std::string TEST_VALUE = "TEST_VALUE"; + +const std::string TEST_NAME_REMOVED = "TEST_NAME_REMOVED"; +const std::string TEST_VALUE_REMOVED = "TEST_VALUE_REMOVED"; + +} // namespace + +BOOST_FIXTURE_TEST_SUITE(LxcppEnvironmentSuite, Fixture) + +using namespace lxcpp; + +BOOST_AUTO_TEST_CASE(SetGetEnv) +{ + pid_t pid = lxcpp::fork(); + if (pid == 0) { + try { + lxcpp::setenv(TEST_NAME, TEST_VALUE); + + if(lxcpp::getenv(TEST_NAME) == TEST_VALUE) { + ::_exit(TEST_PASSED); + } + ::_exit(ERROR); + } catch(...) { + ::_exit(ERROR); + } + } else if (pid > 0) { + int status = -1; + BOOST_REQUIRE(utils::waitPid(pid, status)); + BOOST_REQUIRE(status == TEST_PASSED); + } +} + +BOOST_AUTO_TEST_CASE(ClearEnvExcept) +{ + pid_t pid = lxcpp::fork(); + if (pid == 0) { + try { + lxcpp::setenv(TEST_NAME, TEST_VALUE); + lxcpp::setenv(TEST_NAME_REMOVED, TEST_VALUE_REMOVED); + + clearenvExcept({TEST_NAME}); + + try { + lxcpp::getenv(TEST_NAME_REMOVED); + } catch(const lxcpp::NoSuchValue&) { + if(lxcpp::getenv(TEST_NAME) == TEST_VALUE) { + ::_exit(TEST_PASSED); + } + } + ::_exit(ERROR); + } catch(...) { + ::_exit(ERROR); + } + } else if (pid > 0) { + int status = -1; + BOOST_REQUIRE(utils::waitPid(pid, status)); + BOOST_REQUIRE(status == TEST_PASSED); + } +} + +BOOST_AUTO_TEST_CASE(ClearEnv) +{ + pid_t pid = lxcpp::fork(); + if (pid == 0) { + try { + lxcpp::setenv(TEST_NAME_REMOVED, TEST_VALUE_REMOVED); + lxcpp::clearenv(); + + // clearenv should clear environ + if (::environ) { + ::_exit(ERROR); + } + + try { + lxcpp::getenv(TEST_NAME_REMOVED); + } catch(const lxcpp::NoSuchValue&) { + ::_exit(TEST_PASSED); + } + ::_exit(ERROR); + } catch(...) { + ::_exit(ERROR); + } + } else if (pid > 0) { + int status = -1; + BOOST_REQUIRE(utils::waitPid(pid, status)); + BOOST_REQUIRE(status == TEST_PASSED); + } +} + +BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 21e5a635a691a7c0ab045e1aee74284f340e6f92 Mon Sep 17 00:00:00 2001 From: "Maciej J. Karpiuk" Date: Fri, 28 Aug 2015 15:39:41 +0200 Subject: [PATCH 03/16] server: logging-backend selection via command line. [Feature] command-line option to select logging backend [Cause] logging backend selected in compile-time, no flexibility [Solution] add command-line option, select backend in runtime [Verification] start service with different logging options. Change-Id: I410457521462b29d4c40995b37bbd8ea06e479b4 --- server/main.cpp | 34 ++++++++++++++++++++++++++-------- zone-daemon/main.cpp | 34 +++++++++++++++++++++++++++------- 2 files changed, 53 insertions(+), 15 deletions(-) diff --git a/server/main.cpp b/server/main.cpp index 7ed4ef1..af30cd2 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -58,8 +58,12 @@ const std::string CONFIG_PATH = "/etc/vasum/daemon.conf"; int main(int argc, char* argv[]) { bool runAsRoot = false; - try { +#ifndef NDEBUG + const char *defaultLoggingBackend = "stderr"; +#else + const char *defaultLoggingBackend = "syslog"; +#endif po::options_description desc("Allowed options"); desc.add_options() @@ -67,6 +71,12 @@ int main(int argc, char* argv[]) ("root,r", "Don't drop root privileges at startup") ("daemon,d", "Run server as daemon") ("log-level,l", po::value()->default_value("DEBUG"), "set log level") + ("log-backend,b", po::value()->default_value(defaultLoggingBackend), + "set log backend [stderr,syslog" +#ifdef HAVE_SYSTEMD + ",journal" +#endif + "]") ("check,c", "check runtime environment and exit") ("version,v", "show application version") ; @@ -113,13 +123,22 @@ int main(int argc, char* argv[]) } Logger::setLogLevel(vm["log-level"].as()); -#if !defined(NDEBUG) - Logger::setLogBackend(new StderrBackend()); -#elif HAVE_SYSTEMD - Logger::setLogBackend(new SystemdJournalBackend()); -#else - Logger::setLogBackend(new SyslogBackend()); + const std::string logBackend = vm["log-backend"].as(); + if(logBackend.compare("stderr") == 0) { + Logger::setLogBackend(new StderrBackend()); + } +#ifdef HAVE_SYSTEMD + else if(logBackend.compare("journal") == 0) { + Logger::setLogBackend(new SystemdJournalBackend()); + } #endif + else if(logBackend.compare("syslog") == 0) { + Logger::setLogBackend(new SyslogBackend()); + } + else { + std::cerr << "Error: unrecognized logging backend option: " << logBackend << std::endl; + return 1; + } runAsRoot = vm.count("root") > 0; @@ -149,4 +168,3 @@ int main(int argc, char* argv[]) return 0; } - diff --git a/zone-daemon/main.cpp b/zone-daemon/main.cpp index 1bb3091..82b152e 100644 --- a/zone-daemon/main.cpp +++ b/zone-daemon/main.cpp @@ -55,12 +55,24 @@ const std::string PROGRAM_NAME_AND_VERSION = int main(int argc, char* argv[]) { try { +#ifndef NDEBUG + const char *defaultLoggingBackend = "stderr"; +#else + const char *defaultLoggingBackend = "syslog"; +#endif + po::options_description desc("Allowed options"); desc.add_options() ("help,h", "print this help") ("daemon,d", "Run server as daemon") ("log-level,l", po::value()->default_value("DEBUG"), "set log level") + ("log-backend,b", po::value()->default_value(defaultLoggingBackend), + "set log backend [stderr,syslog" +#ifdef HAVE_SYSTEMD + ",journal" +#endif + "]") ("version,v", "show application version") ; @@ -103,13 +115,22 @@ int main(int argc, char* argv[]) } Logger::setLogLevel(vm["log-level"].as()); -#if !defined(NDEBUG) - Logger::setLogBackend(new StderrBackend()); -#elif HAVE_SYSTEMD - Logger::setLogBackend(new SystemdJournalBackend()); -#else - Logger::setLogBackend(new SyslogBackend()); + const std::string logBackend = vm["log-backend"].as(); + if(logBackend.compare("stderr") == 0) { + Logger::setLogBackend(new StderrBackend()); + } +#ifdef HAVE_SYSTEMD + else if(logBackend.compare("journal") == 0) { + Logger::setLogBackend(new SystemdJournalBackend()); + } #endif + else if(logBackend.compare("syslog") == 0) { + Logger::setLogBackend(new SyslogBackend()); + } + else { + std::cerr << "Error: unrecognized logging backend option: " << logBackend << std::endl; + return 1; + } } catch (std::exception& e) { std::cerr << e.what() << std::endl; @@ -127,4 +148,3 @@ int main(int argc, char* argv[]) return 0; } - -- 2.7.4 From f74e6dababe7066d5184668137cf50800e2f331d Mon Sep 17 00:00:00 2001 From: Lukasz Kostyra Date: Thu, 3 Sep 2015 14:47:47 +0200 Subject: [PATCH 04/16] ipc: Fix critical build break in unique-id [Bug] Build break using Clang due to recently added unique-id code [Cause] Incorrectly used Doxygen syntax causing critical build error [Solution] Correct the syntax. [Verification] Build, install, run tests Change-Id: Ia0194aadfcd5cdcfba90cd518d24fe733edc934b --- libs/ipc/unique-id.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/ipc/unique-id.hpp b/libs/ipc/unique-id.hpp index bceda62..795c2d6 100644 --- a/libs/ipc/unique-id.hpp +++ b/libs/ipc/unique-id.hpp @@ -66,8 +66,8 @@ public: friend std::ostream& operator<<(std::ostream& str, const UniqueID& id); - TimestampType mTime; //< timestamp when generate() was called - UUIDType mUUID; //< random UUID generated with libuuid + TimestampType mTime; ///< timestamp when generate() was called + UUIDType mUUID; ///< random UUID generated with libuuid }; template -- 2.7.4 From c0c76a68a17ee4a7137a8f516087c8389a3eba07 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Wed, 2 Sep 2015 17:04:45 +0200 Subject: [PATCH 05/16] lxcpp: Command implementation [Feature] Base class for commands Attach command [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: Id9ed43c145704f5d9d21f1aa210694fed1615c57 --- .../commands/{attach-manager.cpp => attach.cpp} | 55 ++++++++++++---------- .../commands/{attach-manager.hpp => attach.hpp} | 51 +++++++++++--------- libs/lxcpp/commands/command.hpp | 36 ++++++++++++++ libs/lxcpp/container-impl.cpp | 15 +++--- 4 files changed, 103 insertions(+), 54 deletions(-) rename libs/lxcpp/commands/{attach-manager.cpp => attach.cpp} (71%) rename libs/lxcpp/commands/{attach-manager.hpp => attach.hpp} (54%) create mode 100644 libs/lxcpp/commands/command.hpp diff --git a/libs/lxcpp/commands/attach-manager.cpp b/libs/lxcpp/commands/attach.cpp similarity index 71% rename from libs/lxcpp/commands/attach-manager.cpp rename to libs/lxcpp/commands/attach.cpp index 1a274d3..98a4599 100644 --- a/libs/lxcpp/commands/attach-manager.cpp +++ b/libs/lxcpp/commands/attach.cpp @@ -21,7 +21,7 @@ * @brief Implementation of attaching to a container */ -#include "lxcpp/commands/attach-manager.hpp" +#include "lxcpp/commands/attach.hpp" #include "lxcpp/exception.hpp" #include "lxcpp/process.hpp" #include "lxcpp/filesystem.hpp" @@ -69,7 +69,7 @@ void setupMountPoints() int execFunction(void* call) { try { - return (*static_cast(call))(); + return (*static_cast(call))(); } catch(...) { return -1; // Non-zero on failure } @@ -78,29 +78,35 @@ int execFunction(void* call) } // namespace -AttachManager::AttachManager(lxcpp::ContainerImpl& container) - : mContainer(container) +Attach::Attach(lxcpp::ContainerImpl& container, + Container::AttachCall& userCall, + const int capsToKeep, + const std::string& workDirInContainer, + const std::vector& envToKeep, + const std::vector>& envToSet) + : mContainer(container), + mUserCall(userCall), + mCapsToKeep(capsToKeep), + mWorkDirInContainer(workDirInContainer), + mEnvToKeep(envToKeep), + mEnvToSet(envToSet) { } -AttachManager::~AttachManager() +Attach::~Attach() { } -void AttachManager::attach(Container::AttachCall& userCall, - const int capsToKeep, - const std::string& workDirInContainer, - const std::vector& envToKeep, - const std::vector>& envToSet) +void Attach::execute() { // Channels for setup synchronization utils::Channel intermChannel; - Call call = std::bind(&AttachManager::child, - std::move(userCall), - capsToKeep, - std::move(envToKeep), - std::move(envToSet)); + Call call = std::bind(&Attach::child, + mUserCall, + mCapsToKeep, + mEnvToKeep, + mEnvToSet); const pid_t interPid = lxcpp::fork(); if (interPid > 0) { @@ -109,16 +115,16 @@ void AttachManager::attach(Container::AttachCall& userCall, intermChannel.shutdown(); } else { intermChannel.setRight(); - interm(intermChannel, workDirInContainer, call); + interm(intermChannel, call); intermChannel.shutdown(); ::_exit(0); } } -int AttachManager::child(const Container::AttachCall& call, - const int capsToKeep, - const std::vector& envToKeep, - const std::vector>& envToSet) +int Attach::child(const Container::AttachCall& call, + const int capsToKeep, + const std::vector& envToKeep, + const std::vector>& envToSet) { // Setup capabilities dropCapsFromBoundingExcept(capsToKeep); @@ -134,7 +140,7 @@ int AttachManager::child(const Container::AttachCall& call, return call(); } -void AttachManager::parent(utils::Channel& intermChannel, const pid_t interPid) +void Attach::parent(utils::Channel& intermChannel, const pid_t interPid) { // TODO: Setup cgroups etc const pid_t childPid = intermChannel.read(); @@ -144,15 +150,13 @@ void AttachManager::parent(utils::Channel& intermChannel, const pid_t interPid) lxcpp::waitpid(childPid); } -void AttachManager::interm(utils::Channel& intermChannel, - const std::string& workDirInContainer, - Call& call) +void Attach::interm(utils::Channel& intermChannel, Call& call) { lxcpp::setns(mContainer.getInitPid(), mContainer.getNamespaces()); // Change the current work directory // workDirInContainer is a path relative to the container's root - lxcpp::chdir(workDirInContainer); + lxcpp::chdir(mWorkDirInContainer); // PID namespace won't affect the returned pid // CLONE_PARENT: Child's PPID == Caller's PID @@ -160,7 +164,6 @@ void AttachManager::interm(utils::Channel& intermChannel, &call, CLONE_PARENT); intermChannel.write(childPid); - } } // namespace lxcpp diff --git a/libs/lxcpp/commands/attach-manager.hpp b/libs/lxcpp/commands/attach.hpp similarity index 54% rename from libs/lxcpp/commands/attach-manager.hpp rename to libs/lxcpp/commands/attach.hpp index f286564..342b613 100644 --- a/libs/lxcpp/commands/attach-manager.hpp +++ b/libs/lxcpp/commands/attach.hpp @@ -21,9 +21,10 @@ * @brief Implementation of attaching to a container */ -#ifndef LXCPP_ATTACH_MANAGER_HPP -#define LXCPP_ATTACH_MANAGER_HPP +#ifndef LXCPP_COMMANDS_ATTACH_HPP +#define LXCPP_COMMANDS_ATTACH_HPP +#include "lxcpp/commands/command.hpp" #include "lxcpp/container-impl.hpp" #include "utils/channel.hpp" @@ -31,31 +32,40 @@ namespace lxcpp { -class AttachManager final { +class Attach final: Command { public: typedef std::function Call; - AttachManager(lxcpp::ContainerImpl& container); - ~AttachManager(); - /** - * Runs the call in the container's context + * Runs call in the container's context + * + * Object attach should be used immediately after creation. + * It will not be stored for future use like most other commands. * - * @param call function to run inside container - * @param capsToKeep mask of the capabilities that shouldn't be dropped - * @param workDirInContainer Current Work Directory. Path relative to container's root - * @param envToKeep environment variables to keep in container - * @param envToSet environment variables to add/modify in container + * @param container container to which it attaches + * @param userCall user's function to run + * @param capsToKeep capabilities that will be kept + * @param workDirInContainer work directory set for the new process + * @param envToKeep environment variables that will be kept + * @param envToSet new environment variables that will be set */ - void attach(Container::AttachCall& call, - const int capsToKeep, - const std::string& workDirInContainer, - const std::vector& envToKeep, - const std::vector>& envToSet); + Attach(lxcpp::ContainerImpl& container, + Container::AttachCall& userCall, + const int capsToKeep, + const std::string& workDirInContainer, + const std::vector& envToKeep, + const std::vector>& envToSet); + ~Attach(); -private: + void execute(); +private: const lxcpp::ContainerImpl& mContainer; + const Container::AttachCall& mUserCall; + const int mCapsToKeep; + const std::string& mWorkDirInContainer; + const std::vector& mEnvToKeep; + const std::vector>& mEnvToSet; // Methods for different stages of setting up the attachment static int child(const Container::AttachCall& call, @@ -67,10 +77,9 @@ private: const pid_t pid); void interm(utils::Channel& intermChannel, - const std::string& workDirInContainer, - Container::AttachCall& call); + Call& call); }; } // namespace lxcpp -#endif // LXCPP_ATTACH_MANAGER_HPP \ No newline at end of file +#endif // LXCPP_COMMANDS_ATTACH_HPP \ No newline at end of file diff --git a/libs/lxcpp/commands/command.hpp b/libs/lxcpp/commands/command.hpp new file mode 100644 index 0000000..cd301ee --- /dev/null +++ b/libs/lxcpp/commands/command.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Command interface definition + */ + +#ifndef LXCPP_COMMANDS_COMMAND_HPP +#define LXCPP_COMMANDS_COMMAND_HPP + +namespace lxcpp { + +class Command { +public: + virtual void execute() = 0; +}; + +} // namespace lxcpp + +#endif // LXCPP_COMMANDS_COMMAND_HPP \ No newline at end of file diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp index 0d8d5b1..7189bc7 100644 --- a/libs/lxcpp/container-impl.cpp +++ b/libs/lxcpp/container-impl.cpp @@ -27,7 +27,7 @@ #include "lxcpp/filesystem.hpp" #include "lxcpp/namespace.hpp" #include "lxcpp/capability.hpp" -#include "lxcpp/commands/attach-manager.hpp" +#include "lxcpp/commands/attach.hpp" #include "utils/exception.hpp" @@ -107,13 +107,14 @@ std::string ContainerImpl::getRootPath() void ContainerImpl::attach(Container::AttachCall& call, const std::string& cwdInContainer) { - AttachManager attachManager(*this); + Attach attach(*this, + call, + /*capsToKeep*/ 0, + cwdInContainer, + /*envToKeep*/ {}, + /*envInContainer*/ {{"container","lxcpp"}}); // TODO: Env variables should agree with the ones already in the container - attachManager.attach(call, - /*capsToKeep*/ 0, - cwdInContainer, - /*envToKeep*/ {}, - /*envInContainer*/{{"container","lxcpp"}} ); + attach.execute(); } const std::vector& ContainerImpl::getNamespaces() const -- 2.7.4 From ff9f7d8f7100c3dca173de14e3253e25b677f370 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Thu, 3 Sep 2015 20:50:19 +0200 Subject: [PATCH 06/16] lxcpp: UID/GID setting in Attach [Feature] UID/GID setting [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: Iaa83cab137df53a1391f01c0a29ef236da030aee --- libs/lxcpp/commands/attach.cpp | 25 ++++++++++++++-- libs/lxcpp/commands/attach.hpp | 14 +++++++++ libs/lxcpp/container-impl.cpp | 3 ++ libs/lxcpp/credentials.cpp | 66 ++++++++++++++++++++++++++++++++++++++++++ libs/lxcpp/credentials.hpp | 43 +++++++++++++++++++++++++++ libs/lxcpp/exception.hpp | 5 ++++ 6 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 libs/lxcpp/credentials.cpp create mode 100644 libs/lxcpp/credentials.hpp diff --git a/libs/lxcpp/commands/attach.cpp b/libs/lxcpp/commands/attach.cpp index 98a4599..0ff856e 100644 --- a/libs/lxcpp/commands/attach.cpp +++ b/libs/lxcpp/commands/attach.cpp @@ -28,6 +28,7 @@ #include "lxcpp/namespace.hpp" #include "lxcpp/capability.hpp" #include "lxcpp/environment.hpp" +#include "lxcpp/credentials.hpp" #include "utils/exception.hpp" @@ -80,12 +81,18 @@ int execFunction(void* call) Attach::Attach(lxcpp::ContainerImpl& container, Container::AttachCall& userCall, + const uid_t uid, + const gid_t gid, + const std::vector& supplementaryGids, const int capsToKeep, const std::string& workDirInContainer, const std::vector& envToKeep, const std::vector>& envToSet) : mContainer(container), mUserCall(userCall), + mUid(uid), + mGid(gid), + mSupplementaryGids(supplementaryGids), mCapsToKeep(capsToKeep), mWorkDirInContainer(workDirInContainer), mEnvToKeep(envToKeep), @@ -104,6 +111,9 @@ void Attach::execute() Call call = std::bind(&Attach::child, mUserCall, + mUid, + mGid, + mSupplementaryGids, mCapsToKeep, mEnvToKeep, mEnvToSet); @@ -122,20 +132,29 @@ void Attach::execute() } int Attach::child(const Container::AttachCall& call, + const uid_t uid, + const gid_t gid, + const std::vector& supplementaryGids, const int capsToKeep, const std::vector& envToKeep, const std::vector>& envToSet) { - // Setup capabilities - dropCapsFromBoundingExcept(capsToKeep); - // Setup /proc /sys mount setupMountPoints(); + // Setup capabilities + dropCapsFromBoundingExcept(capsToKeep); + // Setup environment variables clearenvExcept(envToKeep); setenv(envToSet); + // Set uid/gids + lxcpp::setgid(gid); + setgroups(supplementaryGids); + + lxcpp::setuid(uid); + // Run user's code return call(); } diff --git a/libs/lxcpp/commands/attach.hpp b/libs/lxcpp/commands/attach.hpp index 342b613..36c57ba 100644 --- a/libs/lxcpp/commands/attach.hpp +++ b/libs/lxcpp/commands/attach.hpp @@ -28,6 +28,8 @@ #include "lxcpp/container-impl.hpp" #include "utils/channel.hpp" +#include + #include namespace lxcpp { @@ -44,6 +46,9 @@ public: * * @param container container to which it attaches * @param userCall user's function to run + * @param uid uid in the container + * @param gid gid in the container + * @param supplementaryGids supplementary groups in container * @param capsToKeep capabilities that will be kept * @param workDirInContainer work directory set for the new process * @param envToKeep environment variables that will be kept @@ -51,6 +56,9 @@ public: */ Attach(lxcpp::ContainerImpl& container, Container::AttachCall& userCall, + const uid_t uid, + const gid_t gid, + const std::vector& supplementaryGids, const int capsToKeep, const std::string& workDirInContainer, const std::vector& envToKeep, @@ -62,6 +70,9 @@ public: private: const lxcpp::ContainerImpl& mContainer; const Container::AttachCall& mUserCall; + const uid_t mUid; + const gid_t mGid; + const std::vector& mSupplementaryGids; const int mCapsToKeep; const std::string& mWorkDirInContainer; const std::vector& mEnvToKeep; @@ -69,6 +80,9 @@ private: // Methods for different stages of setting up the attachment static int child(const Container::AttachCall& call, + const uid_t uid, + const gid_t gid, + const std::vector& supplementaryGids, const int capsToKeep, const std::vector& envToKeep, const std::vector>& envToSet); diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp index 7189bc7..02e9f3a 100644 --- a/libs/lxcpp/container-impl.cpp +++ b/libs/lxcpp/container-impl.cpp @@ -109,6 +109,9 @@ void ContainerImpl::attach(Container::AttachCall& call, { Attach attach(*this, call, + /*uid in container*/ 0, + /*gid in container*/ 0, + /*supplementary gids in container*/ {}, /*capsToKeep*/ 0, cwdInContainer, /*envToKeep*/ {}, diff --git a/libs/lxcpp/credentials.cpp b/libs/lxcpp/credentials.cpp new file mode 100644 index 0000000..692be25 --- /dev/null +++ b/libs/lxcpp/credentials.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Process credentials handling + */ + +#include "lxcpp/credentials.hpp" +#include "lxcpp/exception.hpp" + +#include "logger/logger.hpp" +#include "utils/exception.hpp" + +#include +#include + +namespace lxcpp { + +void setgroups(const std::vector& gids) +{ + if(-1 == ::setgroups(gids.size(), gids.data())) { + const std::string msg = "setgroups() failed: " + + utils::getSystemErrorMessage(); + LOGE(msg); + throw CredentialSetupException(msg); + } +} + +void setgid(const gid_t gid) +{ + if(-1 == ::setgid(gid)) { + const std::string msg = "setgid() failed: " + + utils::getSystemErrorMessage(); + LOGE(msg); + throw CredentialSetupException(msg); + } +} + +void setuid(const uid_t uid) +{ + if(-1 == ::setuid(uid)) { + const std::string msg = "setuid() failed: " + + utils::getSystemErrorMessage(); + LOGE(msg); + throw CredentialSetupException(msg); + } +} + +} // namespace lxcpp + diff --git a/libs/lxcpp/credentials.hpp b/libs/lxcpp/credentials.hpp new file mode 100644 index 0000000..df00ce5 --- /dev/null +++ b/libs/lxcpp/credentials.hpp @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Jan Olszak (j.olszak@samsung.com) + * @brief Process credentials handling + */ + +#ifndef LXCPP_CREDENTIALS_HPP +#define LXCPP_CREDENTIALS_HPP + +#include + +#include + +namespace lxcpp { + +void setgroups(const std::vector& groups); + +void setgid(const gid_t gid); + +void setuid(const uid_t uid); + + + +} // namespace lxcpp + +#endif // LXCPP_CREDENTIALS_HPP \ No newline at end of file diff --git a/libs/lxcpp/exception.hpp b/libs/lxcpp/exception.hpp index 8c11131..037da41 100644 --- a/libs/lxcpp/exception.hpp +++ b/libs/lxcpp/exception.hpp @@ -56,6 +56,11 @@ struct EnvironmentSetupException: public Exception { : Exception(message) {} }; +struct CredentialSetupException: public Exception { + CredentialSetupException(const std::string& message = "Error during handling environment variables") + : Exception(message) {} +}; + struct CapabilitySetupException: public Exception { CapabilitySetupException(const std::string& message = "Error during a capability operation") : Exception(message) {} -- 2.7.4 From 26530f30e16b55c2de880fe3a9b1d4a767c48287 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Fri, 4 Sep 2015 13:58:47 +0200 Subject: [PATCH 07/16] Adjust tests to lxc-1.1.3 [Feature] Adjust tests to lxc-1.1.3 [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I26d3abed39b60f5072399edcb116567d125d82f0 --- tests/unit_tests/configs/templates/buggy-template.conf | 2 +- tests/unit_tests/configs/templates/console-dbus.conf.in | 2 +- tests/unit_tests/configs/templates/console-ipc.conf.in | 2 +- tests/unit_tests/configs/templates/default.conf | 2 +- tests/unit_tests/configs/templates/minimal.sh | 2 -- tests/unit_tests/configs/templates/missing.conf | 2 +- tests/unit_tests/configs/templates/test-no-shutdown.conf | 2 +- tests/unit_tests/lxc/ut-zone.cpp | 10 +++++----- 8 files changed, 11 insertions(+), 13 deletions(-) diff --git a/tests/unit_tests/configs/templates/buggy-template.conf b/tests/unit_tests/configs/templates/buggy-template.conf index 2ce4024..1f78be4 100644 --- a/tests/unit_tests/configs/templates/buggy-template.conf +++ b/tests/unit_tests/configs/templates/buggy-template.conf @@ -1,6 +1,6 @@ { "zoneTemplate" : "/buggy/path", - "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; read"], + "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; while true; do sleep 0.1; done"], "requestedState" : "running", "ipv4Gateway" : "", "ipv4" : "", diff --git a/tests/unit_tests/configs/templates/console-dbus.conf.in b/tests/unit_tests/configs/templates/console-dbus.conf.in index 1ef567f..2dee28b 100644 --- a/tests/unit_tests/configs/templates/console-dbus.conf.in +++ b/tests/unit_tests/configs/templates/console-dbus.conf.in @@ -1,6 +1,6 @@ { "zoneTemplate" : "minimal.sh", - "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; /bin/dbus-daemon --config-file=@VSM_TEST_CONFIG_INSTALL_DIR@/dbus/ut-dbus-system.conf --fork; read"], + "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; /bin/dbus-daemon --config-file=@VSM_TEST_CONFIG_INSTALL_DIR@/dbus/ut-dbus-system.conf --fork"], "requestedState" : "running", "ipv4Gateway" : "", "ipv4" : "", diff --git a/tests/unit_tests/configs/templates/console-ipc.conf.in b/tests/unit_tests/configs/templates/console-ipc.conf.in index dce9410..5abf8ba 100644 --- a/tests/unit_tests/configs/templates/console-ipc.conf.in +++ b/tests/unit_tests/configs/templates/console-ipc.conf.in @@ -1,6 +1,6 @@ { "zoneTemplate" : "minimal.sh", - "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; read"], + "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; while true; do sleep 0.1; done"], "requestedState" : "running", "ipv4Gateway" : "", "ipv4" : "", diff --git a/tests/unit_tests/configs/templates/default.conf b/tests/unit_tests/configs/templates/default.conf index 276adc9..006b9e4 100644 --- a/tests/unit_tests/configs/templates/default.conf +++ b/tests/unit_tests/configs/templates/default.conf @@ -1,6 +1,6 @@ { "zoneTemplate" : "minimal.sh", - "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; read"], + "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; while true; do sleep 0.1; done"], "requestedState" : "running", "ipv4Gateway" : "", "ipv4" : "", diff --git a/tests/unit_tests/configs/templates/minimal.sh b/tests/unit_tests/configs/templates/minimal.sh index 948cf01..12b921a 100755 --- a/tests/unit_tests/configs/templates/minimal.sh +++ b/tests/unit_tests/configs/templates/minimal.sh @@ -59,8 +59,6 @@ lxc.tty = 0 #lxc.loglevel = TRACE #lxc.logfile = /tmp/${name}.log -lxc.cgroup.devices.deny = a - lxc.mount.auto = proc sys cgroup lxc.mount.entry = /bin bin none ro,bind 0 0 lxc.mount.entry = /etc etc none ro,bind 0 0 diff --git a/tests/unit_tests/configs/templates/missing.conf b/tests/unit_tests/configs/templates/missing.conf index 4d5abd6..88679e5 100644 --- a/tests/unit_tests/configs/templates/missing.conf +++ b/tests/unit_tests/configs/templates/missing.conf @@ -1,6 +1,6 @@ { "zoneTemplate" : "missing.sh", - "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; read"], + "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; while true; do sleep 0.1; done"], "requestedState" : "running", "ipv4Gateway" : "", "ipv4" : "", diff --git a/tests/unit_tests/configs/templates/test-no-shutdown.conf b/tests/unit_tests/configs/templates/test-no-shutdown.conf index 026c3e7..a60520f 100644 --- a/tests/unit_tests/configs/templates/test-no-shutdown.conf +++ b/tests/unit_tests/configs/templates/test-no-shutdown.conf @@ -1,6 +1,6 @@ { "zoneTemplate" : "minimal.sh", - "initWithArgs" : ["/bin/bash"], + "initWithArgs" : ["/bin/bash", "-c", "trap exit SIGTERM; while true; do sleep 0.1; done"], "requestedState" : "running", "ipv4Gateway" : "", "ipv4" : "", diff --git a/tests/unit_tests/lxc/ut-zone.cpp b/tests/unit_tests/lxc/ut-zone.cpp index 7dae96e..47c1414 100644 --- a/tests/unit_tests/lxc/ut-zone.cpp +++ b/tests/unit_tests/lxc/ut-zone.cpp @@ -114,7 +114,7 @@ BOOST_AUTO_TEST_CASE(StartShutdown) const char* argv[] = { "/bin/bash", "-c", - "trap exit SIGTERM; read", + "trap exit SIGTERM; while true; do sleep 0.1; done", NULL }; BOOST_CHECK(lxc.start(argv)); @@ -179,7 +179,7 @@ BOOST_AUTO_TEST_CASE(FreezeUnfreeze) const char* argv[] = { "/bin/bash", "-c", - "trap exit SIGTERM; read", + "trap exit SIGTERM; while true; do sleep 0.1; done", NULL }; BOOST_CHECK(lxc.start(argv)); @@ -202,7 +202,7 @@ BOOST_AUTO_TEST_CASE(FreezeStop) const char* argv[] = { "/bin/bash", "-c", - "trap exit SIGTERM; read", + "trap exit SIGTERM; while true; do sleep 0.1; done", NULL }; BOOST_CHECK(lxc.start(argv)); @@ -226,7 +226,7 @@ BOOST_AUTO_TEST_CASE(Repeat) const char* argv[] = { "/bin/bash", "-c", - "trap exit SIGTERM; read", + "trap exit SIGTERM; while true; do sleep 0.1; done", NULL }; BOOST_CHECK(lxc.start(argv)); @@ -259,7 +259,7 @@ BOOST_AUTO_TEST_CASE(CreateFile) const char* argv[] = { "/bin/bash", "-c", - "trap exit SIGTERM; read", + "trap exit SIGTERM; while true; do sleep 0.1; done", NULL }; BOOST_REQUIRE(lxc.start(argv)); -- 2.7.4 From ba34f2d1fed77882d019c0460007177f50693261 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Wed, 29 Jul 2015 13:27:25 +0200 Subject: [PATCH 08/16] lxcpp: Changes to the ContainerImpl class API for libConfig usage [Feature] Changes to the ContainerImpl class API for libConfig usage. PersistentFileBackend for logger. [Verification] Build, install, run tests. Change-Id: I3e7290df2bf42df9e067fe6734b96dcf5f3aa20b --- libs/logger/backend-persistent-file.cpp | 46 ++++++++++++ libs/logger/backend-persistent-file.hpp | 52 ++++++++++++++ libs/logger/logger.hpp | 2 + libs/lxcpp/container-impl.cpp | 86 +++++++++++++++++------ libs/lxcpp/container-impl.hpp | 55 +++++++++++---- libs/lxcpp/container.hpp | 20 +++--- libs/lxcpp/exception.hpp | 7 +- libs/lxcpp/lxcpp.cpp | 4 +- libs/lxcpp/lxcpp.hpp | 2 +- tests/unit_tests/lxcpp/lxcpp-api-compile-test.cpp | 3 +- tests/unit_tests/lxcpp/ut-container.cpp | 2 +- 11 files changed, 227 insertions(+), 52 deletions(-) create mode 100644 libs/logger/backend-persistent-file.cpp create mode 100644 libs/logger/backend-persistent-file.hpp diff --git a/libs/logger/backend-persistent-file.cpp b/libs/logger/backend-persistent-file.cpp new file mode 100644 index 0000000..8aa53cb --- /dev/null +++ b/libs/logger/backend-persistent-file.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Pawelczyk (l.pawelczyk@samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Lukasz Pawelczyk (l.pawelczyk@samsung.com) + * @brief Persistent file backend for logger + */ + +#include "logger/config.hpp" +#include "logger/formatter.hpp" +#include "logger/backend-persistent-file.hpp" + +#include + +namespace logger { + +void PersistentFileBackend::log(LogLevel logLevel, + const std::string& file, + const unsigned int& line, + const std::string& func, + const std::string& message) +{ + mOut << LogFormatter::getHeader(logLevel, file, line, func); + mOut << message; + mOut << std::endl; + mOut.flush(); +} + + +} // namespace logger diff --git a/libs/logger/backend-persistent-file.hpp b/libs/logger/backend-persistent-file.hpp new file mode 100644 index 0000000..74d2def --- /dev/null +++ b/libs/logger/backend-persistent-file.hpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Lukasz Pawelczyk (l.pawelczyk@samsung.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License + */ + +/** + * @file + * @author Lukasz Pawelczyk (l.pawelczyk@samsung.com) + * @brief Persistent file backend for logger + */ + +#ifndef COMMON_LOGGER_BACKEND_PERSISTENT_FILE_HPP +#define COMMON_LOGGER_BACKEND_PERSISTENT_FILE_HPP + +#include "logger/backend.hpp" + +#include + +namespace logger { + +class PersistentFileBackend : public LogBackend { +public: + PersistentFileBackend(const std::string& filePath) : + mfilePath(filePath), + mOut(mfilePath, std::ios::app) {} + + void log(LogLevel logLevel, + const std::string& file, + const unsigned int& line, + const std::string& func, + const std::string& message) override; +private: + std::string mfilePath; + std::ofstream mOut; +}; + +} // namespace logger + +#endif // COMMON_LOGGER_BACKEND_PERSISTENT_FILE_HPP diff --git a/libs/logger/logger.hpp b/libs/logger/logger.hpp index bedddb0..0a1ebe6 100644 --- a/libs/logger/logger.hpp +++ b/libs/logger/logger.hpp @@ -36,6 +36,7 @@ * Logger::setLogBackend(new NullLogger()); * Logger::setLogBackend(new SystemdJournalBackend()); * Logger::setLogBackend(new FileBackend("/tmp/logs.txt")); + * Logger::setLogBackend(new PersistentFileBackend("/tmp/logs.txt")); * Logger::setLogBackend(new SyslogBackend()); * Logger::setLogBackend(new StderrBackend()); * @@ -62,6 +63,7 @@ #include "logger/level.hpp" #include "logger/backend-file.hpp" #include "logger/backend-stderr.hpp" +#include "logger/backend-persistent-file.hpp" #include #include diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp index 02e9f3a..73e5254 100644 --- a/libs/lxcpp/container-impl.cpp +++ b/libs/lxcpp/container-impl.cpp @@ -29,77 +29,118 @@ #include "lxcpp/capability.hpp" #include "lxcpp/commands/attach.hpp" +#include "logger/logger.hpp" #include "utils/exception.hpp" #include #include +#include +#include +#include + namespace lxcpp { -ContainerImpl::ContainerImpl() +ContainerImpl::ContainerImpl(const std::string &name, const std::string &path) { -} + if (name.empty()) { + const std::string msg = "Name cannot be empty"; + LOGE(msg); + throw ConfigureException(msg); + } -ContainerImpl::~ContainerImpl() -{ + if (path.empty()) { + const std::string msg = "Path cannot be empty"; + LOGE(msg); + throw ConfigureException(msg); + } + + if(::access(path.c_str(), X_OK) < 0) { + const std::string msg = "Path must point to a traversable directory"; + LOGE(msg); + throw ConfigureException(msg); + } + + mConfig.mName = name; + mConfig.mRootPath = path; } -std::string ContainerImpl::getName() +// TODO: the aim of this constructor is to create a new ContainerImpl based on an already +// running container. It should talk to its guard and receive its current config. +ContainerImpl::ContainerImpl(pid_t /*guardPid*/) { throw NotImplementedException(); } -void ContainerImpl::setName(const std::string& /* name */) +ContainerImpl::~ContainerImpl() { - throw NotImplementedException(); } -void ContainerImpl::start() +const std::string& ContainerImpl::getName() const { - throw NotImplementedException(); + return mConfig.mName; } -void ContainerImpl::stop() +const std::string& ContainerImpl::getRootPath() const { - throw NotImplementedException(); + return mConfig.mRootPath; } -void ContainerImpl::freeze() +const std::vector& ContainerImpl::getInit() { - throw NotImplementedException(); + return mConfig.mInit; } -void ContainerImpl::unfreeze() +void ContainerImpl::setInit(const std::vector &init) { - throw NotImplementedException(); + if (init.empty() || init[0].empty()) { + const std::string msg = "Init path cannot be empty"; + LOGE(msg); + throw ConfigureException(msg); + } + + std::string path = mConfig.mRootPath + "/" + init[0]; + + if (::access(path.c_str(), X_OK) < 0) { + const std::string msg = "Init path must point to an executable file"; + LOGE(msg); + throw ConfigureException(msg); + } + + mConfig.mInit = init; } -void ContainerImpl::reboot() +pid_t ContainerImpl::getGuardPid() const { - throw NotImplementedException(); + return mConfig.mGuardPid; } pid_t ContainerImpl::getInitPid() const { - return mInitPid; + return mConfig.mInitPid; } -void ContainerImpl::create() +void ContainerImpl::start() { throw NotImplementedException(); } -void ContainerImpl::destroy() +void ContainerImpl::stop() { throw NotImplementedException(); } -void ContainerImpl::setRootPath(const std::string& /* path */) +void ContainerImpl::freeze() { throw NotImplementedException(); } -std::string ContainerImpl::getRootPath() +void ContainerImpl::unfreeze() +{ + throw NotImplementedException(); +} + +void ContainerImpl::reboot() { throw NotImplementedException(); } @@ -125,7 +166,6 @@ const std::vector& ContainerImpl::getNamespaces() const return mNamespaces; } - void ContainerImpl::addInterfaceConfig(const std::string& hostif, const std::string& zoneif, InterfaceType type, diff --git a/libs/lxcpp/container-impl.hpp b/libs/lxcpp/container-impl.hpp index c862473..5435d49 100644 --- a/libs/lxcpp/container-impl.hpp +++ b/libs/lxcpp/container-impl.hpp @@ -24,6 +24,11 @@ #ifndef LXCPP_CONTAINER_IMPL_HPP #define LXCPP_CONTAINER_IMPL_HPP +#include +#include +#include +#include + #include "lxcpp/container.hpp" #include "lxcpp/namespace.hpp" #include "lxcpp/network.hpp" @@ -32,28 +37,50 @@ namespace lxcpp { +struct ContainerConfig { + std::string mName; + std::string mRootPath; + pid_t mGuardPid; + pid_t mInitPid; + std::vector mInit; + + ContainerConfig() : mGuardPid(-1), mInitPid(-1) {} + + CONFIG_REGISTER + ( + mName, + mRootPath, + mGuardPid, + mInitPid, + mInit + ) +}; + + class ContainerImpl : public virtual Container { public: - ContainerImpl(); + ContainerImpl(const std::string &name, const std::string &path); + ContainerImpl(pid_t guardPid); ~ContainerImpl(); - std::string getName(); - void setName(const std::string& name); + // Configuration + const std::string& getName() const; + const std::string& getRootPath() const; + + pid_t getGuardPid() const; + pid_t getInitPid() const; - //Execution actions + const std::vector& getInit(); + void setInit(const std::vector &init); + + const std::vector& getNamespaces() const; + + // Execution actions void start(); void stop(); void freeze(); void unfreeze(); void reboot(); - pid_t getInitPid() const; - const std::vector& getNamespaces() const; - - //Filesystem actions - void create(); - void destroy(); - void setRootPath(const std::string& path); - std::string getRootPath(); // Other void attach(Container::AttachCall& attachCall, @@ -80,7 +107,9 @@ public: void delAddr(const std::string& ifname, const InetAddr& addr); private: - pid_t mInitPid; + ContainerConfig mConfig; + + // TODO: convert to ContainerConfig struct std::vector mNamespaces; std::vector mInterfaceConfig; }; diff --git a/libs/lxcpp/container.hpp b/libs/lxcpp/container.hpp index 882aa87..192f2df 100644 --- a/libs/lxcpp/container.hpp +++ b/libs/lxcpp/container.hpp @@ -50,22 +50,22 @@ public: virtual ~Container() {}; - virtual std::string getName() = 0; - virtual void setName(const std::string& name) = 0; + // Configuration + virtual const std::string& getName() const = 0; + virtual const std::string& getRootPath() const = 0; - //Execution actions + virtual pid_t getGuardPid() const = 0; + virtual pid_t getInitPid() const = 0; + + virtual const std::vector& getInit() = 0; + virtual void setInit(const std::vector &init) = 0; + + // Execution actions virtual void start() = 0; virtual void stop() = 0; virtual void freeze() = 0; virtual void unfreeze() = 0; virtual void reboot() = 0; - virtual pid_t getInitPid() const = 0; - - //Filesystem actions - virtual void create() = 0; - virtual void destroy() = 0; - virtual void setRootPath(const std::string& path) = 0; - virtual std::string getRootPath() = 0; // Other virtual void attach(AttachCall& attachCall, diff --git a/libs/lxcpp/exception.hpp b/libs/lxcpp/exception.hpp index 037da41..af81779 100644 --- a/libs/lxcpp/exception.hpp +++ b/libs/lxcpp/exception.hpp @@ -42,7 +42,7 @@ struct NotImplementedException: public Exception { }; struct ProcessSetupException: public Exception { - ProcessSetupException(const std::string& message = "Error during setting up a process") + ProcessSetupException(const std::string& message = "Error while setting up a process") : Exception(message) {} }; @@ -81,6 +81,11 @@ struct NetworkException : public Exception { : Exception(message) {} }; +struct ConfigureException: public Exception { + ConfigureException(const std::string& message = "Error while configuring a container") + : Exception(message) {} +}; + } // namespace lxcpp #endif // LXCPP_EXCEPTION_HPP diff --git a/libs/lxcpp/lxcpp.cpp b/libs/lxcpp/lxcpp.cpp index 97c3866..35cd3d6 100644 --- a/libs/lxcpp/lxcpp.cpp +++ b/libs/lxcpp/lxcpp.cpp @@ -25,9 +25,9 @@ namespace lxcpp { -Container* createContainer() +Container* createContainer(const std::string& name, const std::string& path) { - return new ContainerImpl(); + return new ContainerImpl(name, path); } } // namespace lxcpp diff --git a/libs/lxcpp/lxcpp.hpp b/libs/lxcpp/lxcpp.hpp index 5eb3f57..c2b3029 100644 --- a/libs/lxcpp/lxcpp.hpp +++ b/libs/lxcpp/lxcpp.hpp @@ -28,7 +28,7 @@ namespace lxcpp { -Container* createContainer(); +Container* createContainer(const std::string &name, const std::string &path); } // namespace lxcpp diff --git a/tests/unit_tests/lxcpp/lxcpp-api-compile-test.cpp b/tests/unit_tests/lxcpp/lxcpp-api-compile-test.cpp index 2e72bfb..f6d48c2 100644 --- a/tests/unit_tests/lxcpp/lxcpp-api-compile-test.cpp +++ b/tests/unit_tests/lxcpp/lxcpp-api-compile-test.cpp @@ -27,6 +27,7 @@ using namespace lxcpp; int main(int /*argc*/, const char * /*argv*/ []) { - Container* c = createContainer(); + Container* c = createContainer("Name", "/"); + delete c; } diff --git a/tests/unit_tests/lxcpp/ut-container.cpp b/tests/unit_tests/lxcpp/ut-container.cpp index 6177502..35672e0 100644 --- a/tests/unit_tests/lxcpp/ut-container.cpp +++ b/tests/unit_tests/lxcpp/ut-container.cpp @@ -44,7 +44,7 @@ using namespace lxcpp; BOOST_AUTO_TEST_CASE(ConstructorDestructor) { - auto c = createContainer(); + auto c = createContainer("FirstTestContainer", "/"); delete c; } -- 2.7.4 From 500d09337df5b74b5f292b8d0d275607de1aa1b1 Mon Sep 17 00:00:00 2001 From: "Maciej J. Karpiuk" Date: Fri, 4 Sep 2015 16:39:29 +0200 Subject: [PATCH 09/16] server: file logging added to logging backends [Feature] new logging backend support: file [Cause] N/A [Solution] one more option to logging-backend [Verification] try to log to file and user specified filename Change-Id: Iae51c076c1b52439ff6388cf50b85dc14165a59e --- server/main.cpp | 15 +++++++++++++-- zone-daemon/main.cpp | 15 +++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/server/main.cpp b/server/main.cpp index af30cd2..81f908f 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -64,7 +64,8 @@ int main(int argc, char* argv[]) #else const char *defaultLoggingBackend = "syslog"; #endif - po::options_description desc("Allowed options"); + // 100 - wider terminal, nicer option descriptions + po::options_description desc("Allowed options", 100); desc.add_options() ("help,h", "print this help") @@ -72,11 +73,13 @@ int main(int argc, char* argv[]) ("daemon,d", "Run server as daemon") ("log-level,l", po::value()->default_value("DEBUG"), "set log level") ("log-backend,b", po::value()->default_value(defaultLoggingBackend), - "set log backend [stderr,syslog" + "set log backend [stderr,syslog,file" #ifdef HAVE_SYSTEMD ",journal" #endif "]") + ("log-file,f", po::value()->default_value("vasum.log"), + "set filename for file logging, optional") ("check,c", "check runtime environment and exit") ("version,v", "show application version") ; @@ -127,6 +130,14 @@ int main(int argc, char* argv[]) if(logBackend.compare("stderr") == 0) { Logger::setLogBackend(new StderrBackend()); } + else if(logBackend.compare("file") == 0) { + const std::string logFilename = vm["log-file"].as(); + if(logFilename.empty()) { + std::cerr << "Error: invalid log file provided for file logging backend" << std::endl; + return 1; + } + Logger::setLogBackend(new FileBackend(logFilename)); + } #ifdef HAVE_SYSTEMD else if(logBackend.compare("journal") == 0) { Logger::setLogBackend(new SystemdJournalBackend()); diff --git a/zone-daemon/main.cpp b/zone-daemon/main.cpp index 82b152e..4e59091 100644 --- a/zone-daemon/main.cpp +++ b/zone-daemon/main.cpp @@ -61,18 +61,21 @@ int main(int argc, char* argv[]) const char *defaultLoggingBackend = "syslog"; #endif - po::options_description desc("Allowed options"); + // 100 - wider terminal, nicer option descriptions + po::options_description desc("Allowed options", 100); desc.add_options() ("help,h", "print this help") ("daemon,d", "Run server as daemon") ("log-level,l", po::value()->default_value("DEBUG"), "set log level") ("log-backend,b", po::value()->default_value(defaultLoggingBackend), - "set log backend [stderr,syslog" + "set log backend [stderr,syslog,file" #ifdef HAVE_SYSTEMD ",journal" #endif "]") + ("log-file,f", po::value()->default_value("zoned.log"), + "set filename for file logging, optional") ("version,v", "show application version") ; @@ -119,6 +122,14 @@ int main(int argc, char* argv[]) if(logBackend.compare("stderr") == 0) { Logger::setLogBackend(new StderrBackend()); } + else if(logBackend.compare("file") == 0) { + const std::string logFilename = vm["log-file"].as(); + if(logFilename.empty()) { + std::cerr << "Error: invalid log file provided for file logging backend" << std::endl; + return 1; + } + Logger::setLogBackend(new FileBackend(logFilename)); + } #ifdef HAVE_SYSTEMD else if(logBackend.compare("journal") == 0) { Logger::setLogBackend(new SystemdJournalBackend()); -- 2.7.4 From 3b14d399c8dfe556cd4a253db8e06e4f4ce79633 Mon Sep 17 00:00:00 2001 From: "Maciej J. Karpiuk" Date: Fri, 4 Sep 2015 12:45:38 +0200 Subject: [PATCH 10/16] libIpc: doxygen docs added [Feature] libIpc doxygen docs enabled and enhanced [Cause] documentation task in progress, libIpc was not yet included [Solution] write missing docs, create group [Verification] build docs and check libIpc module Change-Id: Ic8e5261200da9714b478461fe830fabbaa3b5bc9 --- libs/ipc/client.hpp | 99 +++++++++++++++++++++++-------- libs/ipc/epoll/event-poll.hpp | 54 ++++++++++++++++- libs/ipc/epoll/events.hpp | 12 +++- libs/ipc/exception.hpp | 36 ++++++++++- libs/ipc/internals/processor.hpp | 17 +++--- libs/ipc/method-result.hpp | 4 ++ libs/ipc/service.hpp | 125 +++++++++++++++++++++++++++++---------- libs/ipc/types.hpp | 54 ++++++++++++++++- 8 files changed, 330 insertions(+), 71 deletions(-) diff --git a/libs/ipc/client.hpp b/libs/ipc/client.hpp index e083166..a26ccbc 100644 --- a/libs/ipc/client.hpp +++ b/libs/ipc/client.hpp @@ -19,6 +19,7 @@ /** * @file * @author Jan Olszak (j.olszak@samsung.com) + * @defgroup libIpc libIpc * @brief Handling client connections */ @@ -36,29 +37,68 @@ namespace ipc { /** - * This class wraps communication via UX sockets for client applications. + * @brief This class wraps communication via UX sockets for client applications. * It uses serialization mechanism from Config. * - * For message format @see ipc::Processor + * @code + * // eventPoll - epoll wrapper class + * // address - server socket address + * ipc::epoll::EventPoll examplePoll; + * ipc::Client myClient(examplePoll, address); + * myClient.start(); // connect to the service + * // call method synchronously + * const auto result = mClient.callSync( + * api::ipc::METHOD_GET_ZONE_ID_LIST, + * std::make_shared()); + * // call method asynchronously + * // first: declare lambda function to call on completion + * auto asyncResult = [result](ipc::Result&& out) { + * if (out.isValid()) { + * // got successful response! + * } + * }; + * std::string id = "example_zone_id"; + * mClient.callAsync(api::ipc::METHOD_DESTROY_ZONE, + * std::make_shared(api::ZoneId{id}), + * asyncResult); + * @endcode + * + * @see libConfig + * @see ipc::Processor + * @see ipc::epoll::EventPoll + * + * @ingroup libIpc */ class Client { public: /** - * @param eventPoll event poll - * @param serverPath path to the server's socket + * Constructs the Client, but doesn't start it. + * Once set-up, call start() to connect client to the server. + * + * @param eventPoll event poll + * @param serverPath path to the server's socket */ Client(epoll::EventPoll& eventPoll, const std::string& serverPath); ~Client(); + /** + * Copying Client class is prohibited. + */ Client(const Client&) = delete; + /** + * Copying Client class is prohibited. + */ Client& operator=(const Client&) = delete; /** * Starts processing + * @note if the Client is already running, it quits immediately (no exception thrown) */ void start(); /** + * Is the communication thread running? + * * @return is the communication thread running */ bool isStarted(); @@ -66,21 +106,23 @@ public: /** * Stops processing * - * @param wait does it block waiting for all internals to stop + * @param wait should the call block while waiting for all internals to stop? By default true - do block. */ void stop(bool wait = true); /** * Set the callback called for each new connection to a peer * - * @param newPeerCallback the callback + * @param newPeerCallback the callback to call on new connection event + * @note if callback is already set, it will be overridden */ void setNewPeerCallback(const PeerCallback& newPeerCallback); /** * Set the callback called when connection to a peer is lost * - * @param removedPeerCallback the callback + * @param removedPeerCallback the callback to call on peer disconnected event + * @note if callback is already set, it will be overridden */ void setRemovedPeerCallback(const PeerCallback& removedPeerCallback); @@ -89,8 +131,10 @@ public: * When a message with the given method id is received * the data will be parsed and passed to this callback. * - * @param methodID API dependent id of the method - * @param method method handling implementation + * @param methodID API dependent id of the method + * @param method method handling implementation + * @tparam SentDataType data type to send + * @tparam ReceivedDataType data type to receive */ template void setMethodHandler(const MethodID methodID, @@ -101,28 +145,32 @@ public: * When a message with the given method id is received * the data will be parsed and passed to this callback. * - * @param methodID API dependent id of the method - * @param signal signal handling implementation - * @tparam ReceivedDataType data type to serialize + * @param methodID API dependent id of the method + * @param signal data processing callback + * @tparam ReceivedDataType data type to receive */ template void setSignalHandler(const MethodID methodID, const typename SignalHandler::type& signal); /** - * Removes the callback + * Removes the callback associated with specific method id. * - * @param methodID API dependent id of the method + * @param methodID API dependent id of the method + * @see setMethodHandler() + * @see setSignalHandler() */ void removeMethod(const MethodID methodID); /** * Synchronous method call. * - * @param methodID API dependent id of the method - * @param data data to send - * @param timeoutMS how long to wait for the return value before throw - * @return result data + * @param methodID API dependent id of the method + * @param data data to send + * @param timeoutMS optional, how long to wait for the return value before throw (milliseconds, default: 5000) + * @tparam SentDataType data type to send + * @tparam ReceivedDataType data type to receive + * @return pointer to the call result data */ template std::shared_ptr callSync(const MethodID methodID, @@ -133,10 +181,11 @@ public: * Asynchronous method call. The return callback will be called on * return data arrival. It will be run in the PROCESSOR thread. * - * - * @param methodID API dependent id of the method - * @param data data to send - * @param resultCallback callback for result serialization and handling + * @param methodID API dependent id of the method + * @param data data to send + * @param resultCallback callback processing the return data + * @tparam SentDataType data type to send + * @tparam ReceivedDataType data type to receive */ template void callAsync(const MethodID methodID, @@ -148,9 +197,9 @@ public: * There is no return value from the peer * Sends any data only if a peer registered this a signal * - * @param methodID API dependent id of the method - * @param data data to sent - * @tparam SentDataType data type to send + * @param methodID API dependent id of the method + * @param data data to send + * @tparam SentDataType data type to send */ template void signal(const MethodID methodID, diff --git a/libs/ipc/epoll/event-poll.hpp b/libs/ipc/epoll/event-poll.hpp index ba82497..ceb5717 100644 --- a/libs/ipc/epoll/event-poll.hpp +++ b/libs/ipc/epoll/event-poll.hpp @@ -35,23 +35,71 @@ namespace ipc { namespace epoll { +/** + * @brief This class waits on registered file descriptor for events. + * It uses epoll mechanism. + * + * @see ipc::epoll::Events + * + * @ingroup Types + */ class EventPoll { public: + /** + * Generic function type used as callback for epoll events. + * + * @param fd descriptor that triggered the event + * @param events event mask that occured + * @see ipc::epoll::Events + */ typedef std::function Callback; + /** + * Constructs the EventPoll and initializes the underlaying epoll mechanism. + * @throw UtilsException thrown if epoll initialization failed + */ EventPoll(); ~EventPoll(); + /** + * Returns epoll handle. + * @return handle or -1 if not initialized + */ int getPollFD() const; + /** + * Add descriptor and it's watched events. + * + * @param fd descriptor to watch + * @param events events to associate with the descriptor + * @param callback callback to call once the event occurs + * @throw UtilsException thrown if descriptor already registered or add fail + * @see ipc::epoll::Events + */ void addFD(const int fd, const Events events, Callback&& callback); + + /** + * Modify watched events for descriptor. + * @param fd watched descriptor, already registered + * @param events events to associate with the descriptor + * @throw UtilsException if descriptor not found or epoll modify fail + * @see ipc::epoll::Events + */ void modifyFD(const int fd, const Events events); + + /** + * Remove descriptor from the watch list. + * @param fd watched descriptor + */ void removeFD(const int fd); /** - * Dispatch at most one signaled FD - * @param timeoutMs how long should wait in case of no pending events - * (0 - return immediately, -1 - wait forever) + * Wait for events on descriptor on the watch list. + * Dispatch at most one signaled FD. + * + * @param timeoutMs how long should wait in case of no pending events + * (0 - return immediately, -1 - wait forever) + * @throw UtilsException if epoll_wait fails * @return false on timeout */ bool dispatchIteration(const int timeoutMs); diff --git a/libs/ipc/epoll/events.hpp b/libs/ipc/epoll/events.hpp index 093542b..219bcd2 100644 --- a/libs/ipc/epoll/events.hpp +++ b/libs/ipc/epoll/events.hpp @@ -31,8 +31,18 @@ namespace ipc { namespace epoll { -typedef unsigned int Events; ///< bitmask of EPOLL* constants +/** + * @brief bitmask of EPOLL* constants + * @ingroup Types + */ +typedef unsigned int Events; +/** + * Convert event mask into readable string. + * Values will be comma separated. + * @param events event type mask to convert + * @return string describing the mask + */ std::string eventsToString(Events events); } // namespace epoll diff --git a/libs/ipc/exception.hpp b/libs/ipc/exception.hpp index 271cf9a..140619c 100644 --- a/libs/ipc/exception.hpp +++ b/libs/ipc/exception.hpp @@ -31,48 +31,82 @@ namespace ipc { /** - * Base class for exceptions in IPC + * @brief Base class for all exceptions in libIpc. + * @ingroup Types + * @defgroup IPCException IPCException */ struct IPCException: public std::runtime_error { IPCException(const std::string& message) : std::runtime_error(message) {} }; +/** + * Exception to indicate error while reading/parsing data from the socket. + * @ingroup IPCException + */ struct IPCParsingException: public IPCException { IPCParsingException(const std::string& message = "Exception during reading/parsing data from the socket") : IPCException(message) {} }; +/** + * Exception to indicate error while writing/serializing data to the socket. + * @ingroup IPCException + */ struct IPCSerializationException: public IPCException { IPCSerializationException(const std::string& message = "Exception during writing/serializing data to the socket") : IPCException(message) {} }; +/** + * Exception to indicate that requested peer is not available, i.e. might got disconnected. + * @ingroup IPCException + */ struct IPCPeerDisconnectedException: public IPCException { IPCPeerDisconnectedException(const std::string& message = "No such peer. Might got disconnected.") : IPCException(message) {} }; +/** + * Exception to indicate that peer performed a forbidden action. + * @ingroup IPCException + */ struct IPCNaughtyPeerException: public IPCException { IPCNaughtyPeerException(const std::string& message = "Peer performed a forbidden action.") : IPCException(message) {} }; +/** + * Exception to indicate error while removing peer + * @ingroup IPCException + */ struct IPCRemovedPeerException: public IPCException { IPCRemovedPeerException(const std::string& message = "Removing peer") : IPCException(message) {} }; +/** + * Exception to indicate error while closing IPC channel + * @ingroup IPCException + */ struct IPCClosingException: public IPCException { IPCClosingException(const std::string& message = "Closing IPC") : IPCException(message) {} }; +/** + * Exception to indicate timeout event error + * @ingroup IPCException + */ struct IPCTimeoutException: public IPCException { IPCTimeoutException(const std::string& message) : IPCException(message) {} }; +/** + * Exception to indicate user error + * @ingroup IPCException + */ struct IPCUserException: public IPCException { IPCUserException(const int code, const std::string& message) : IPCException(message), diff --git a/libs/ipc/internals/processor.hpp b/libs/ipc/internals/processor.hpp index 2706792..e383a57 100644 --- a/libs/ipc/internals/processor.hpp +++ b/libs/ipc/internals/processor.hpp @@ -246,21 +246,24 @@ public: const MessageID messageID); /** - * Removes the callback + * Removes the callback associated with specific method id. * - * @param methodID API dependent id of the method + * @param methodID API dependent id of the method + * @see setMethodHandler() + * @see setSignalHandler() */ void removeMethod(const MethodID methodID); /** * Synchronous method call. * - * @param methodID API dependent id of the method - * @param peerID id of the peer - * @param data data to send - * @param timeoutMS how long to wait for the return value before throw - * @tparam SentDataType data type to send + * @param methodID API dependent id of the method + * @param peerID id of the peer + * @param data data to send + * @param timeoutMS optional, how long to wait for the return value before throw (milliseconds, default: 5000) + * @tparam SentDataType data type to send * @tparam ReceivedDataType data type to receive + * @return call result data */ template std::shared_ptr callSync(const MethodID methodID, diff --git a/libs/ipc/method-result.hpp b/libs/ipc/method-result.hpp index 26369ed..c1729f7 100644 --- a/libs/ipc/method-result.hpp +++ b/libs/ipc/method-result.hpp @@ -33,6 +33,10 @@ namespace ipc { class Processor; +/** + * @brief Class used to obtain method call result code. + * @ingroup Types + */ class MethodResult { public: typedef std::shared_ptr Pointer; diff --git a/libs/ipc/service.hpp b/libs/ipc/service.hpp index 5e73a71..a5f7c86 100644 --- a/libs/ipc/service.hpp +++ b/libs/ipc/service.hpp @@ -38,28 +38,72 @@ namespace ipc { /** - * This class wraps communication via UX sockets. + * @brief This class wraps communication via UX sockets. * It uses serialization mechanism from Config. * - * For message format @see ipc::Processor + * @code + * // eventPoll - epoll wrapper class + * // address - server socket address + * ipc::epoll::EventPoll examplePoll; + * // create callbacks for connected / disconnected events + * ipc::PeerCallback connectedCallback = [this](const ipc::PeerID peerID, + * const ipc::FileDescriptor) { + * // new connection came! + * }; + * ipc::PeerCallback disconnectedCallback = [this](const ipc::PeerID peerID, + * const ipc::FileDescriptor) { + * // connection disconnected! + * }; + * // create the service + * ipc::Service myService(eventPoll, "/tmp/example_service.socket", + * connectedCallback, disconnectedCallback)); + * // add example method handler + * auto exampleMethodHandler = [&](const PeerID, std::shared_ptr& data, MethodResult::Pointer methodResult) { + * // got example method call! Incoming data in "data" argument + * // respond with some data + * auto returnData = std::make_shared(data->intVal); + * methodResult->set(returnData); + * }; + * const MethodID exampleMethodID = 1234; + * myService.setMethodHandler(exampleMethodID, exampleMethodHandler); + * myService.start(); // start the service, clients may connect via /tmp/example_service.socket + * @endcode + * + * @see libConfig + * @see ipc::Processor + * + * @ingroup libIpc */ class Service { public: /** - * @param eventPoll event poll - * @param path path to the socket + * Constructs the Service, but doesn't start it. + * The object is ready to add methods. + * Once set-up, call start() to start the service. + * + * @param eventPoll event poll + * @param path path to the socket + * @param addPeerCallback optional on new peer connection callback + * @param removePeerCallback optional on peer removal callback */ Service(epoll::EventPoll& eventPoll, const std::string& path, const PeerCallback& addPeerCallback = nullptr, const PeerCallback& removePeerCallback = nullptr); - ~Service(); + virtual ~Service(); + /** + * Copying Service class is prohibited. + */ Service(const Service&) = delete; + /** + * Copying Service class is prohibited. + */ Service& operator=(const Service&) = delete; /** * Starts processing + * @note if the service is already running, it quits immediately (no exception thrown) */ void start(); @@ -71,62 +115,79 @@ public: /** * Stops all working threads * - * @param wait does it block waiting for all internals to stop + * @param wait should the call block while waiting for all internals to stop? By default true - do block. */ void stop(bool wait = true); /** * Set the callback called for each new connection to a peer * - * @param newPeerCallback the callback + * @param newPeerCallback the callback to call on new connection event + * @note if callback is already set, it will be overridden */ void setNewPeerCallback(const PeerCallback& newPeerCallback); /** * Set the callback called when connection to a peer is lost * - * @param removedPeerCallback the callback + * @param removedPeerCallback the callback to call on peer disconnected event + * @note if callback is already set, it will be overridden */ void setRemovedPeerCallback(const PeerCallback& removedPeerCallback); /** - * Saves the callback connected to the method id. - * When a message with the given method id is received - * the data will be parsed and passed to this callback. + * Saves the callbacks connected to the method id. + * When a message with the given method id is received, + * the data will be passed to the serialization callback through file descriptor. + * + * Then the process callback will be called with the parsed data. * - * @param methodID API dependent id of the method - * @param method method handling implementation + * @param methodID API dependent id of the method + * @param method data processing callback + * @tparam SentDataType data type to send + * @tparam ReceivedDataType data type to receive */ template void setMethodHandler(const MethodID methodID, const typename MethodHandler::type& method); /** - * Saves the callback connected to the method id. - * When a message with the given method id is received - * the data will be parsed and passed to this callback. + * Saves the callbacks connected to the method id. + * When a message with the given method id is received, + * the data will be passed to the serialization callback through file descriptor. + * + * Then the process callback will be called with the parsed data. + * There is no return data to send back. * - * @param methodID API dependent id of the method - * @param handler handling implementation - * @tparam ReceivedDataType data type to serialize + * Adding signal sends a registering message to all peers + * + * @param methodID API dependent id of the method + * @param handler data processing callback + * @tparam ReceivedDataType data type to receive */ template void setSignalHandler(const MethodID methodID, const typename SignalHandler::type& handler); /** - * Removes the callback + * Removes the callback associated with specific method id. * - * @param methodID API dependent id of the method + * @param methodID API dependent id of the method + * @see setMethodHandler() + * @see setSignalHandler() */ void removeMethod(const MethodID methodID); /** * Synchronous method call. * - * @param methodID API dependent id of the method - * @param data data to send - * @return result data + * @param methodID API dependent id of the method + * @param peerID id of the peer + * @param data data to send + * @param timeoutMS optional, how long to wait for the return value before throw (milliseconds, default: 5000) + * @tparam SentDataType data type to send + * @tparam ReceivedDataType data type to receive + * @return pointer to the call result data */ template std::shared_ptr callSync(const MethodID methodID, @@ -138,10 +199,12 @@ public: * Asynchronous method call. The return callback will be called on * return data arrival. It will be run in the PROCESSOR thread. * - * - * @param methodID API dependent id of the method - * @param data data to send - * @param resultCallback callback for result serialization and handling + * @param methodID API dependent id of the method + * @param peerID id of the peer + * @param data data to send + * @param resultCallback callback processing the return data + * @tparam SentDataType data type to send + * @tparam ReceivedDataType data type to receive */ template void callAsync(const MethodID methodID, @@ -154,9 +217,9 @@ public: * There is no return value from the peer * Sends any data only if a peer registered this a signal * - * @param methodID API dependent id of the method - * @param data data to sent - * @tparam SentDataType data type to send + * @param methodID API dependent id of the method + * @param data data to send + * @tparam SentDataType data type to send */ template void signal(const MethodID methodID, diff --git a/libs/ipc/types.hpp b/libs/ipc/types.hpp index fad01b3..c9b270b 100644 --- a/libs/ipc/types.hpp +++ b/libs/ipc/types.hpp @@ -31,19 +31,67 @@ namespace ipc { +/** + * @brief Generic types used in libIpc. + * + * @ingroup libIpc + * @defgroup Types libIpc tools + */ + typedef int FileDescriptor; typedef unsigned int MethodID; typedef std::string MessageID; typedef std::string PeerID; -typedef std::function PeerCallback; -typedef std::function& data)> SerializeCallback; -typedef std::function(int fd)> ParseCallback; +/** + * Generic function type used as callback for peer events. + * + * @param peerID peer identifier that event relates to + * @param fd event origin + * @ingroup Types + */ +typedef std::function PeerCallback; + +/** + * Generic function type used as callback for serializing and + * saving serialized data to the descriptor. + * + * @param fd descriptor to save the serialized data to + * @param data data to serialize + * @ingroup Types + */ +typedef std::function& data)> SerializeCallback; + +/** + * Generic function type used as callback for reading and parsing data. + * + * @param fd descriptor to read the data from + * @ingroup Types + */ +typedef std::function(ipc::FileDescriptor fd)> ParseCallback; +/** + * Generate an unique message id. + * + * @return new, unique MessageID + * @ingroup Types + */ MessageID getNextMessageID(); + +/** + * Generate an unique peer id. + * + * @return new, unique PeerID + * @ingroup Types + */ PeerID getNextPeerID(); +/** + * Generic type used as a callback function for handling signals. + * @tparam ReceivedDataType type of received data + * @ingroup Types + */ template struct SignalHandler { typedef std::function Date: Tue, 1 Sep 2015 16:14:23 +0200 Subject: [PATCH 11/16] Add colorful output for the CLI [Feature] Colorful CLI output [Cause] N/A [Solution] N/A [Verification] Build, install, run CLI Change-Id: I2123fbd6c5b94ed20eaa278ce00e371e86ff61f0 --- cli/main.cpp | 132 ++++++++++++++++++++++++++++++--------- cli/support/vsm-completion.sh.in | 5 +- 2 files changed, 104 insertions(+), 33 deletions(-) diff --git a/cli/main.cpp b/cli/main.cpp index 537ad69..7320490 100644 --- a/cli/main.cpp +++ b/cli/main.cpp @@ -24,6 +24,7 @@ #include "command-line-interface.hpp" #include "cli-exception.hpp" +#include "utils/ccolor.hpp" #include #include @@ -38,17 +39,48 @@ #include #include #include +#include #include #include using namespace vasum::cli; -namespace fs = boost::filesystem; +namespace fs = boost::filesystem; +namespace po = boost::program_options; namespace { static int interactiveMode = 0; +static bool useColors = false; + +const std::string getStrongColor() +{ + if (useColors) { + return utils::getConsoleEscapeSequence(utils::Attributes::BOLD, utils::Color::RED); + } else { + return ""; + } +} + +const std::string getBoldColor() +{ + if (useColors) { + return utils::getConsoleEscapeSequence(utils::Attributes::BOLD, utils::Color::GREEN); + } else { + return ""; + } +} + +const std::string getDefaultColor() +{ + if (useColors) { + return utils::getConsoleEscapeSequence(utils::Attributes::DEFAULT, utils::Color::DEFAULT); + } else { + return ""; + } +} + std::vector commands = { { create_zone, @@ -257,12 +289,13 @@ void printUsage(std::ostream& out, const std::string& name, unsigned int mode) if (mode == MODE_COMMAND_LINE) { out << "Description:\n" << "\tCommand line tool to manage vasum containers.\n" - << "\tCalled without parameters enters interactive mode.\n" + << "\tCalled without positional parameters enters interactive mode.\n\n" << "Options:\n" - << "\t-h,help print this help\n" - << "\t-f read and execute commands from file\n\n"; + << "\t-h,help print this help\n" + << "\t-f read and execute commands from file\n" + << "\t--color=[=WHEN] colorize the output. WHEN can be never, always or auto\n\n"; } - out << "command can be one of the following:\n"; + out << "Command can be one of the following:\n"; for (const auto& command : commands) { if (command.isAvailable(mode)) { @@ -278,7 +311,8 @@ void printUsage(std::ostream& out, const std::string& name, unsigned int mode) } } - out << "\nType '" << n << "command help' to read about a specific one.\n"; + out << "\nType '" << n << getStrongColor() << "command help" + << getDefaultColor() << "' to read about a specific one.\n"; } int connect() @@ -407,10 +441,11 @@ static int processStream(std::istream& stream) } int rc = EXIT_FAILURE; + const std::string prompt = getBoldColor() + "vsm> " + getDefaultColor(); std::string ln; - while (readline_from("vsm> ", stream, ln)) { + while (readline_from(prompt, stream, ln)) { if (ln.empty() || ln[0] == '#') { //skip empty line or comment - continue; + continue; } std::istringstream iss(ln); @@ -446,7 +481,7 @@ static int processFile(const std::string& fn) void printList(const std::vector& list) { for (const auto& i : list) { - std::cout << i << std::endl; + std::cout << getBoldColor() << i << getDefaultColor() << std::endl; } } @@ -482,23 +517,23 @@ int bashComplMode(int argc, const char *argv[]) return rc; } -int cliMode(const int argc, const char** argv) +int cliMode(const int argc, const char* name, const char** argv) { - if (std::string(argv[1]) == "-h" || std::string(argv[1]) == "help") { - printUsage(std::cout, argv[0], MODE_COMMAND_LINE); - return EXIT_SUCCESS; - } - - if (commandMap.find(argv[1]) == commandMap.end()) { - printUsage(std::cout, argv[0], MODE_COMMAND_LINE); - return EXIT_FAILURE; - } + if (argc > 0) { + if (std::string(argv[0]) == "-h" || std::string(argv[0]) == "help") { + printUsage(std::cout, name, MODE_COMMAND_LINE); + return EXIT_SUCCESS; + } - // pass all the arguments excluding argv[0] - the executable name - Args commandArgs(argv + 1, argv + argc); - int rc = executeCommand(commandArgs, MODE_COMMAND_LINE); + if (commandMap.find(argv[0]) == commandMap.end()) { + printUsage(std::cout, name, MODE_COMMAND_LINE); + return EXIT_FAILURE; + } - return rc; + Args commandArgs(argv, argv + argc); + return executeCommand(commandArgs, MODE_COMMAND_LINE); + } + return EXIT_SUCCESS; } fs::path getHomePath() { @@ -506,6 +541,30 @@ fs::path getHomePath() { return fs::path(h ? h : ""); } +void setColorUsage(const std::string& value) { + if (value == "always") { + useColors = true; + } else if (value == "never"){ + useColors = false; + } else if (value == "auto") { + if (isatty(fileno(stdout)) == 1) { + useColors = true; + } else { + useColors = false; + } + } +} + +bool checkColorOption(const std::string& arg) { + const std::string colorOption = "--color="; + if (arg.find(colorOption) == 0) { + const std::string value = arg.substr(colorOption.length()); + setColorUsage(value); + return true; + } else { + return false; + } +} } // namespace @@ -518,26 +577,39 @@ int main(const int argc, const char *argv[]) int rc = EXIT_FAILURE; if (argc > 1) { - //process arguments if (std::string(argv[1]) == "--bash-completion") { - rc = bashComplMode(argc - 2, argv + 2); + interactiveMode = MODE_COMMAND_LINE; + int argShift; + if (argc > 2) { + argShift = (checkColorOption(argv[2]) ? 1 : 0) + 2; + } else { + argShift = 2; + } + useColors = false; + rc = bashComplMode(argc - argShift, argv + argShift); } else if (std::string(argv[1]) == "-f") { + interactiveMode = MODE_COMMAND_LINE; if (argc < 3) { std::cerr << "Filename expected" << std::endl; rc = EXIT_FAILURE; - } - else { + } else { rc = processFile(std::string(argv[2])); } } else { - rc = cliMode(argc, argv); + int argShift = (checkColorOption(argv[1]) ? 1 : 0) + 1; + + if (argc - argShift > 0) { + interactiveMode = MODE_COMMAND_LINE; + rc = cliMode(argc - argShift, argv[0], argv + argShift); + } } + } - } else { + if (interactiveMode != MODE_COMMAND_LINE) { fs::path historyfile(".vsm_history"); - if (isatty(0) == 1) { + if (isatty(fileno(stdin)) == 1) { fs::path home = getHomePath(); if (!home.empty()) { historyfile = home / historyfile; diff --git a/cli/support/vsm-completion.sh.in b/cli/support/vsm-completion.sh.in index 1177348..74a02a5 100755 --- a/cli/support/vsm-completion.sh.in +++ b/cli/support/vsm-completion.sh.in @@ -2,9 +2,8 @@ [ -z "$BASH_VERSION" ] && return __@PROJECT_NAME@_cli() { - local exe=$1 cur=$2 prev=$3 - words=`@CLI_CODENAME@ --bash-completion "${COMP_WORDS[@]:1}"` - COMPREPLY=($(compgen -W "$words" -- $cur)) + words=`@CLI_CODENAME@ --bash-completion ${COMP_WORDS[COMP_CWORD]}` + COMPREPLY=($(compgen -W "$words" -- ${COMP_WORDS[COMP_CWORD]})) } complete -F __@PROJECT_NAME@_cli vsm -- 2.7.4 From 9c895ec3e042205df243e175a06967a975d8f645 Mon Sep 17 00:00:00 2001 From: Pawel Kubik Date: Mon, 7 Sep 2015 11:17:45 +0200 Subject: [PATCH 12/16] cppcheck fixes [Feature] Small code fixes based on cppcheck [Cause] Minimizing possible runtime errors [Solution] Fix the code using cppcheck suggestions, suppress false-positives [Verification] Compile, run cppcheck Change-Id: I94fab8e50879f78f3ccb503fd18606e9cbfabfb5 --- cli/cli-exception.hpp | 4 +-- client/exception.hpp | 10 +++--- client/vasum-client-impl.cpp | 1 - common/api/ipc-method-result-builder.hpp | 2 +- common/base-exception.hpp | 2 +- common/lxc/exception.hpp | 4 +-- common/utils/exception.hpp | 4 +-- libs/dbus/exception.hpp | 10 +++--- libs/ipc/exception.hpp | 16 +++++----- libs/ipc/internals/finish-request.hpp | 2 +- libs/ipc/internals/method-request.hpp | 6 ++-- libs/ipc/internals/processor.cpp | 26 ++++++++-------- libs/ipc/internals/processor.hpp | 46 ++++++++++++++-------------- libs/ipc/internals/remove-peer-request.hpp | 2 +- libs/ipc/internals/result-builder.hpp | 10 ++---- libs/ipc/internals/send-result-request.hpp | 4 +-- libs/ipc/internals/signal-request.hpp | 6 ++-- libs/ipc/method-result.cpp | 6 ++-- libs/ipc/method-result.hpp | 6 ++-- libs/ipc/service.hpp | 8 ++--- libs/lxcpp/exception.hpp | 22 ++++++------- server/exception.hpp | 14 ++++----- server/zones-manager.cpp | 4 +-- tests/cppcheck/cppcheck.sh | 4 ++- tests/cppcheck/cppcheck.suppress | 23 ++++++++++++-- tests/unit_tests/ipc/ut-ipc.cpp | 2 +- tests/unit_tests/server/ut-zones-manager.cpp | 11 +++---- tests/unit_tests/utils/ut-worker.cpp | 2 +- zone-daemon/exception.hpp | 2 +- 29 files changed, 135 insertions(+), 124 deletions(-) diff --git a/cli/cli-exception.hpp b/cli/cli-exception.hpp index 982f52d..f0d5e0f 100644 --- a/cli/cli-exception.hpp +++ b/cli/cli-exception.hpp @@ -38,12 +38,12 @@ namespace cli { */ struct CliException: public VasumException { - CliException(const std::string& error) : VasumException(error) {} + explicit CliException(const std::string& error) : VasumException(error) {} }; struct IOException: public CliException { - IOException(const std::string& error) : CliException(error) {} + explicit IOException(const std::string& error) : CliException(error) {} }; } // namespace cli diff --git a/client/exception.hpp b/client/exception.hpp index d4be66b..98ebf81 100644 --- a/client/exception.hpp +++ b/client/exception.hpp @@ -37,27 +37,27 @@ namespace vasum { */ struct ClientException: public VasumException { - ClientException(const std::string& error) : VasumException(error) {} + explicit ClientException(const std::string& error) : VasumException(error) {} }; struct IOException: public ClientException { - IOException(const std::string& error) : ClientException(error) {} + explicit IOException(const std::string& error) : ClientException(error) {} }; struct OperationFailedException: public ClientException { - OperationFailedException(const std::string& error) : ClientException(error) {} + explicit OperationFailedException(const std::string& error) : ClientException(error) {} }; struct InvalidArgumentException: public ClientException { - InvalidArgumentException(const std::string& error) : ClientException(error) {} + explicit InvalidArgumentException(const std::string& error) : ClientException(error) {} }; struct InvalidResponseException: public ClientException { - InvalidResponseException(const std::string& error) : ClientException(error) {} + explicit InvalidResponseException(const std::string& error) : ClientException(error) {} }; } diff --git a/client/vasum-client-impl.cpp b/client/vasum-client-impl.cpp index e3aca1d..41cc919 100644 --- a/client/vasum-client-impl.cpp +++ b/client/vasum-client-impl.cpp @@ -899,4 +899,3 @@ VsmStatus Client::vsm_clean_up_zones_root() noexcept std::make_shared()); }); } - diff --git a/common/api/ipc-method-result-builder.hpp b/common/api/ipc-method-result-builder.hpp index e9554d0..cad5d8a 100644 --- a/common/api/ipc-method-result-builder.hpp +++ b/common/api/ipc-method-result-builder.hpp @@ -40,7 +40,7 @@ const std::string IPC_CONNECTION_PREFIX = "ipc://"; class IPCMethodResultBuilder: public MethodResultBuilder { public: - IPCMethodResultBuilder(const ipc::MethodResult::Pointer& methodResult); + explicit IPCMethodResultBuilder(const ipc::MethodResult::Pointer& methodResult); ~IPCMethodResultBuilder() {} private: diff --git a/common/base-exception.hpp b/common/base-exception.hpp index 645fa41..05e1fd6 100644 --- a/common/base-exception.hpp +++ b/common/base-exception.hpp @@ -38,7 +38,7 @@ namespace vasum { */ struct VasumException: public std::runtime_error { - VasumException(const std::string& error) : std::runtime_error(error) {} + explicit VasumException(const std::string& error) : std::runtime_error(error) {} }; } // namespace vasum diff --git a/common/lxc/exception.hpp b/common/lxc/exception.hpp index 379fe43..40c7d5f 100644 --- a/common/lxc/exception.hpp +++ b/common/lxc/exception.hpp @@ -37,12 +37,12 @@ namespace vasum { */ struct LxcException: public VasumException { - LxcException(const std::string& error) : VasumException(error) {} + explicit LxcException(const std::string& error) : VasumException(error) {} }; struct KeyNotFoundException: public LxcException { - KeyNotFoundException(const std::string& error) : LxcException(error) {} + explicit KeyNotFoundException(const std::string& error) : LxcException(error) {} }; } // namespace vasum diff --git a/common/utils/exception.hpp b/common/utils/exception.hpp index fda0554..232b090 100644 --- a/common/utils/exception.hpp +++ b/common/utils/exception.hpp @@ -36,12 +36,12 @@ namespace utils { */ struct UtilsException: public std::runtime_error { - UtilsException(const std::string& error) : std::runtime_error(error) {} + explicit UtilsException(const std::string& error) : std::runtime_error(error) {} }; struct ProvisionExistsException: public UtilsException { - ProvisionExistsException(const std::string& error) : UtilsException(error) {} + explicit ProvisionExistsException(const std::string& error) : UtilsException(error) {} }; /** diff --git a/libs/dbus/exception.hpp b/libs/dbus/exception.hpp index a09bdbc..b38877c 100644 --- a/libs/dbus/exception.hpp +++ b/libs/dbus/exception.hpp @@ -34,7 +34,7 @@ namespace dbus { */ struct DbusException: public std::runtime_error { - DbusException(const std::string& error = "") : std::runtime_error(error) {} + explicit DbusException(const std::string& error = "") : std::runtime_error(error) {} }; /** @@ -42,7 +42,7 @@ struct DbusException: public std::runtime_error { */ struct DbusIOException: public DbusException { - DbusIOException(const std::string& error = "") : DbusException(error) {} + explicit DbusIOException(const std::string& error = "") : DbusException(error) {} }; /** @@ -50,7 +50,7 @@ struct DbusIOException: public DbusException { */ struct DbusOperationException: public DbusException { - DbusOperationException(const std::string& error = "") : DbusException(error) {} + explicit DbusOperationException(const std::string& error = "") : DbusException(error) {} }; /** @@ -58,7 +58,7 @@ struct DbusOperationException: public DbusException { */ struct DbusCustomException: public DbusException { - DbusCustomException(const std::string& error = "") : DbusException(error) {} + explicit DbusCustomException(const std::string& error = "") : DbusException(error) {} }; /** @@ -66,7 +66,7 @@ struct DbusCustomException: public DbusException { */ struct DbusInvalidArgumentException: public DbusException { - DbusInvalidArgumentException(const std::string& error = "") : DbusException(error) {} + explicit DbusInvalidArgumentException(const std::string& error = "") : DbusException(error) {} }; } // namespace dbus diff --git a/libs/ipc/exception.hpp b/libs/ipc/exception.hpp index 140619c..3fe7a5b 100644 --- a/libs/ipc/exception.hpp +++ b/libs/ipc/exception.hpp @@ -36,7 +36,7 @@ namespace ipc { * @defgroup IPCException IPCException */ struct IPCException: public std::runtime_error { - IPCException(const std::string& message) + explicit IPCException(const std::string& message) : std::runtime_error(message) {} }; @@ -45,7 +45,7 @@ struct IPCException: public std::runtime_error { * @ingroup IPCException */ struct IPCParsingException: public IPCException { - IPCParsingException(const std::string& message = "Exception during reading/parsing data from the socket") + explicit IPCParsingException(const std::string& message = "Exception during reading/parsing data from the socket") : IPCException(message) {} }; @@ -54,7 +54,7 @@ struct IPCParsingException: public IPCException { * @ingroup IPCException */ struct IPCSerializationException: public IPCException { - IPCSerializationException(const std::string& message = "Exception during writing/serializing data to the socket") + explicit IPCSerializationException(const std::string& message = "Exception during writing/serializing data to the socket") : IPCException(message) {} }; @@ -63,7 +63,7 @@ struct IPCSerializationException: public IPCException { * @ingroup IPCException */ struct IPCPeerDisconnectedException: public IPCException { - IPCPeerDisconnectedException(const std::string& message = "No such peer. Might got disconnected.") + explicit IPCPeerDisconnectedException(const std::string& message = "No such peer. Might got disconnected.") : IPCException(message) {} }; @@ -72,7 +72,7 @@ struct IPCPeerDisconnectedException: public IPCException { * @ingroup IPCException */ struct IPCNaughtyPeerException: public IPCException { - IPCNaughtyPeerException(const std::string& message = "Peer performed a forbidden action.") + explicit IPCNaughtyPeerException(const std::string& message = "Peer performed a forbidden action.") : IPCException(message) {} }; @@ -81,7 +81,7 @@ struct IPCNaughtyPeerException: public IPCException { * @ingroup IPCException */ struct IPCRemovedPeerException: public IPCException { - IPCRemovedPeerException(const std::string& message = "Removing peer") + explicit IPCRemovedPeerException(const std::string& message = "Removing peer") : IPCException(message) {} }; @@ -90,7 +90,7 @@ struct IPCRemovedPeerException: public IPCException { * @ingroup IPCException */ struct IPCClosingException: public IPCException { - IPCClosingException(const std::string& message = "Closing IPC") + explicit IPCClosingException(const std::string& message = "Closing IPC") : IPCException(message) {} }; @@ -99,7 +99,7 @@ struct IPCClosingException: public IPCException { * @ingroup IPCException */ struct IPCTimeoutException: public IPCException { - IPCTimeoutException(const std::string& message) + explicit IPCTimeoutException(const std::string& message) : IPCException(message) {} }; diff --git a/libs/ipc/internals/finish-request.hpp b/libs/ipc/internals/finish-request.hpp index 5a948bd..934c135 100644 --- a/libs/ipc/internals/finish-request.hpp +++ b/libs/ipc/internals/finish-request.hpp @@ -43,4 +43,4 @@ public: } // namespace ipc -#endif // COMMON_IPC_INTERNALS_FINISH_REQUEST_HPP \ No newline at end of file +#endif // COMMON_IPC_INTERNALS_FINISH_REQUEST_HPP diff --git a/libs/ipc/internals/method-request.hpp b/libs/ipc/internals/method-request.hpp index 663cbde..53d9d44 100644 --- a/libs/ipc/internals/method-request.hpp +++ b/libs/ipc/internals/method-request.hpp @@ -41,7 +41,7 @@ public: template static std::shared_ptr create(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& process); @@ -54,7 +54,7 @@ public: ResultBuilderHandler process; private: - MethodRequest(const MethodID methodID, const PeerID peerID) + MethodRequest(const MethodID methodID, const PeerID& peerID) : methodID(methodID), peerID(peerID), messageID(getNextMessageID()) @@ -64,7 +64,7 @@ private: template std::shared_ptr MethodRequest::create(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& process) { diff --git a/libs/ipc/internals/processor.cpp b/libs/ipc/internals/processor.cpp index fdbcbe8..164d735 100644 --- a/libs/ipc/internals/processor.cpp +++ b/libs/ipc/internals/processor.cpp @@ -92,7 +92,7 @@ Processor::Peers::iterator Processor::getPeerInfoIterator(const FileDescriptor f }); } -Processor::Peers::iterator Processor::getPeerInfoIterator(const PeerID peerID) +Processor::Peers::iterator Processor::getPeerInfoIterator(const PeerID & peerID) { return std::find_if(mPeerInfo.begin(), mPeerInfo.end(), [peerID](const PeerInfo & peerInfo) { return peerID == peerInfo.peerID; @@ -162,16 +162,16 @@ FileDescriptor Processor::getEventFD() } void Processor::sendResult(const MethodID methodID, - const PeerID peerID, - const MessageID messageID, + const PeerID& peerID, + const MessageID& messageID, const std::shared_ptr& data) { auto requestPtr = std::make_shared(methodID, peerID, messageID, data); mRequestQueue.pushFront(Event::SEND_RESULT, requestPtr); } -void Processor::sendError(const PeerID peerID, - const MessageID messageID, +void Processor::sendError(const PeerID& peerID, + const MessageID& messageID, const int errorCode, const std::string& message) { @@ -180,8 +180,8 @@ void Processor::sendError(const PeerID peerID, } void Processor::sendVoid(const MethodID methodID, - const PeerID peerID, - const MessageID messageID) + const PeerID& peerID, + const MessageID& messageID) { auto data = std::make_shared(); auto requestPtr = std::make_shared(methodID, peerID, messageID, data); @@ -208,7 +208,7 @@ PeerID Processor::addPeer(const std::shared_ptr& socketPtr) return requestPtr->peerID; } -void Processor::removePeerSyncInternal(const PeerID peerID, Lock& lock) +void Processor::removePeerSyncInternal(const PeerID& peerID, Lock& lock) { LOGS(mLogPrefix + "Processor removePeer peerID: " << peerID); @@ -329,7 +329,7 @@ bool Processor::handleInput(const FileDescriptor fd) } } -void Processor::onNewSignals(const PeerID peerID, std::shared_ptr& data) +void Processor::onNewSignals(const PeerID& peerID, std::shared_ptr& data) { LOGS(mLogPrefix + "Processor onNewSignals peerID: " << peerID); @@ -338,7 +338,7 @@ void Processor::onNewSignals(const PeerID peerID, std::shared_ptr& data) +void Processor::onErrorSignal(const PeerID&, std::shared_ptr& data) { LOGS(mLogPrefix + "Processor onErrorSignal messageID: " << data->messageID); @@ -351,7 +351,7 @@ void Processor::onErrorSignal(const PeerID, std::shared_ptr signalCallbacks) { LOGS(mLogPrefix + "Processor onRemoteSignal; methodID: " << methodID << " messageID: " << messageID); @@ -422,7 +422,7 @@ bool Processor::onRemoteSignal(Peers::iterator& peerIt, bool Processor::onRemoteMethod(Peers::iterator& peerIt, const MethodID methodID, - const MessageID messageID, + const MessageID& messageID, std::shared_ptr methodCallbacks) { LOGS(mLogPrefix + "Processor onRemoteMethod; methodID: " << methodID << " messageID: " << messageID); diff --git a/libs/ipc/internals/processor.hpp b/libs/ipc/internals/processor.hpp index e383a57..91edfc1 100644 --- a/libs/ipc/internals/processor.hpp +++ b/libs/ipc/internals/processor.hpp @@ -217,8 +217,8 @@ public: * @param data data to send */ void sendResult(const MethodID methodID, - const PeerID peerID, - const MessageID messageID, + const PeerID& peerID, + const MessageID& messageID, const std::shared_ptr& data); /** @@ -229,8 +229,8 @@ public: * @param errorCode code of the error * @param message description of the error */ - void sendError(const PeerID peerID, - const MessageID messageID, + void sendError(const PeerID& peerID, + const MessageID& messageID, const int errorCode, const std::string& message); @@ -242,8 +242,8 @@ public: * @param messageID id of the message to which it replies */ void sendVoid(const MethodID methodID, - const PeerID peerID, - const MessageID messageID); + const PeerID& peerID, + const MessageID& messageID); /** * Removes the callback associated with specific method id. @@ -267,7 +267,7 @@ public: */ template std::shared_ptr callSync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, unsigned int timeoutMS = 5000); @@ -283,7 +283,7 @@ public: */ template MessageID callAsync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& process); @@ -352,7 +352,7 @@ private: struct RegisterSignalsProtocolMessage { RegisterSignalsProtocolMessage() = default; - RegisterSignalsProtocolMessage(const std::vector& ids) + explicit RegisterSignalsProtocolMessage(const std::vector& ids) : ids(ids) {} std::vector ids; @@ -365,7 +365,7 @@ private: struct ErrorProtocolMessage { ErrorProtocolMessage() = default; - ErrorProtocolMessage(const MessageID messageID, const int code, const std::string& message) + ErrorProtocolMessage(const MessageID& messageID, const int code, const std::string& message) : messageID(messageID), code(code), message(message) {} MessageID messageID; @@ -461,7 +461,7 @@ private: template MessageID callAsyncInternal(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& process); @@ -475,7 +475,7 @@ private: template void signalInternal(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data); // Request handlers @@ -487,28 +487,28 @@ private: bool onFinishRequest(FinishRequest& request); bool onReturnValue(Peers::iterator& peerIt, - const MessageID messageID); + const MessageID& messageID); bool onRemoteMethod(Peers::iterator& peerIt, const MethodID methodID, - const MessageID messageID, + const MessageID& messageID, std::shared_ptr methodCallbacks); bool onRemoteSignal(Peers::iterator& peerIt, const MethodID methodID, - const MessageID messageID, + const MessageID& messageID, std::shared_ptr signalCallbacks); void removePeerInternal(Peers::iterator peerIt, const std::exception_ptr& exceptionPtr); - void removePeerSyncInternal(const PeerID peerID, Lock& lock); + void removePeerSyncInternal(const PeerID& peerID, Lock& lock); - void onNewSignals(const PeerID peerID, + void onNewSignals(const PeerID& peerID, std::shared_ptr& data); - void onErrorSignal(const PeerID peerID, + void onErrorSignal(const PeerID& peerID, std::shared_ptr& data); Peers::iterator getPeerInfoIterator(const FileDescriptor fd); - Peers::iterator getPeerInfoIterator(const PeerID peerID); + Peers::iterator getPeerInfoIterator(const PeerID& peerID); }; @@ -616,7 +616,7 @@ void Processor::setSignalHandler(const MethodID methodID, template MessageID Processor::callAsync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& process) { @@ -626,7 +626,7 @@ MessageID Processor::callAsync(const MethodID methodID, template MessageID Processor::callAsyncInternal(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& process) { @@ -638,7 +638,7 @@ MessageID Processor::callAsyncInternal(const MethodID methodID, template std::shared_ptr Processor::callSync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, unsigned int timeoutMS) { @@ -692,7 +692,7 @@ std::shared_ptr Processor::callSync(const MethodID methodID, template void Processor::signalInternal(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data) { auto requestPtr = SignalRequest::create(methodID, peerID, data); diff --git a/libs/ipc/internals/remove-peer-request.hpp b/libs/ipc/internals/remove-peer-request.hpp index c9f7ec7..e124227 100644 --- a/libs/ipc/internals/remove-peer-request.hpp +++ b/libs/ipc/internals/remove-peer-request.hpp @@ -37,7 +37,7 @@ public: RemovePeerRequest(const RemovePeerRequest&) = delete; RemovePeerRequest& operator=(const RemovePeerRequest&) = delete; - RemovePeerRequest(const PeerID peerID, + RemovePeerRequest(const PeerID& peerID, const std::shared_ptr& conditionPtr) : peerID(peerID), conditionPtr(conditionPtr) diff --git a/libs/ipc/internals/result-builder.hpp b/libs/ipc/internals/result-builder.hpp index 97134e3..b9c9471 100644 --- a/libs/ipc/internals/result-builder.hpp +++ b/libs/ipc/internals/result-builder.hpp @@ -39,12 +39,12 @@ public: mExceptionPtr(nullptr) {} - ResultBuilder(const std::exception_ptr& exceptionPtr) + explicit ResultBuilder(const std::exception_ptr& exceptionPtr) : mData(nullptr), mExceptionPtr(exceptionPtr) {} - ResultBuilder(const std::shared_ptr& data) + explicit ResultBuilder(const std::shared_ptr& data) : mData(data), mExceptionPtr(nullptr) @@ -68,9 +68,3 @@ typedef std::function ResultBuilderHandler; } // namespace ipc #endif // COMMON_IPC_RESULT_BUILDER_HPP - - - - - - diff --git a/libs/ipc/internals/send-result-request.hpp b/libs/ipc/internals/send-result-request.hpp index a6ed2b4..de512c0 100644 --- a/libs/ipc/internals/send-result-request.hpp +++ b/libs/ipc/internals/send-result-request.hpp @@ -36,8 +36,8 @@ public: SendResultRequest& operator=(const SendResultRequest&) = delete; SendResultRequest(const MethodID methodID, - const PeerID peerID, - const MessageID messageID, + const PeerID& peerID, + const MessageID& messageID, const std::shared_ptr& data) : methodID(methodID), peerID(peerID), diff --git a/libs/ipc/internals/signal-request.hpp b/libs/ipc/internals/signal-request.hpp index 904d3f3..aa597c0 100644 --- a/libs/ipc/internals/signal-request.hpp +++ b/libs/ipc/internals/signal-request.hpp @@ -38,7 +38,7 @@ public: template static std::shared_ptr create(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data); MethodID methodID; @@ -48,7 +48,7 @@ public: SerializeCallback serialize; private: - SignalRequest(const MethodID methodID, const PeerID peerID) + SignalRequest(const MethodID methodID, const PeerID& peerID) : methodID(methodID), peerID(peerID), messageID(getNextMessageID()) @@ -58,7 +58,7 @@ private: template std::shared_ptr SignalRequest::create(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data) { std::shared_ptr request(new SignalRequest(methodID, peerID)); diff --git a/libs/ipc/method-result.cpp b/libs/ipc/method-result.cpp index 97eb450..f110689 100644 --- a/libs/ipc/method-result.cpp +++ b/libs/ipc/method-result.cpp @@ -31,8 +31,8 @@ namespace ipc { MethodResult::MethodResult(Processor& processor, const MethodID methodID, - const MessageID messageID, - const PeerID peerID) + const MessageID& messageID, + const PeerID& peerID) : mProcessor(processor), mMethodID(methodID), mPeerID(peerID), @@ -54,7 +54,7 @@ void MethodResult::setError(const int code, const std::string& message) mProcessor.sendError(mPeerID, mMessageID, code, message); } -PeerID MethodResult::getPeerID() +PeerID MethodResult::getPeerID() const { return mPeerID; } diff --git a/libs/ipc/method-result.hpp b/libs/ipc/method-result.hpp index c1729f7..c6fce37 100644 --- a/libs/ipc/method-result.hpp +++ b/libs/ipc/method-result.hpp @@ -43,8 +43,8 @@ public: MethodResult(Processor& processor, const MethodID methodID, - const MessageID messageID, - const PeerID peerID); + const MessageID& messageID, + const PeerID& peerID); template @@ -55,7 +55,7 @@ public: void setVoid(); void setError(const int code, const std::string& message); - PeerID getPeerID(); + PeerID getPeerID() const; private: Processor& mProcessor; diff --git a/libs/ipc/service.hpp b/libs/ipc/service.hpp index a5f7c86..6d953dd 100644 --- a/libs/ipc/service.hpp +++ b/libs/ipc/service.hpp @@ -191,7 +191,7 @@ public: */ template std::shared_ptr callSync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, unsigned int timeoutMS = 5000); @@ -208,7 +208,7 @@ public: */ template void callAsync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& resultCallback); @@ -251,7 +251,7 @@ void Service::setSignalHandler(const MethodID methodID, template std::shared_ptr Service::callSync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, unsigned int timeoutMS) { @@ -263,7 +263,7 @@ std::shared_ptr Service::callSync(const MethodID methodID, template void Service::callAsync(const MethodID methodID, - const PeerID peerID, + const PeerID& peerID, const std::shared_ptr& data, const typename ResultHandler::type& resultCallback) { diff --git a/libs/lxcpp/exception.hpp b/libs/lxcpp/exception.hpp index af81779..7764282 100644 --- a/libs/lxcpp/exception.hpp +++ b/libs/lxcpp/exception.hpp @@ -32,57 +32,57 @@ namespace lxcpp { * Base class for exceptions in lxcpp */ struct Exception: public std::runtime_error { - Exception(const std::string& message) + explicit Exception(const std::string& message) : std::runtime_error(message) {} }; struct NotImplementedException: public Exception { - NotImplementedException(const std::string& message = "Functionality not yet implemented") + explicit NotImplementedException(const std::string& message = "Functionality not yet implemented") : Exception(message) {} }; struct ProcessSetupException: public Exception { - ProcessSetupException(const std::string& message = "Error while setting up a process") + explicit ProcessSetupException(const std::string& message = "Error while setting up a process") : Exception(message) {} }; struct FileSystemSetupException: public Exception { - FileSystemSetupException(const std::string& message = "Error during a file system operation") + explicit FileSystemSetupException(const std::string& message = "Error during a file system operation") : Exception(message) {} }; struct EnvironmentSetupException: public Exception { - EnvironmentSetupException(const std::string& message = "Error during handling environment variables") + explicit EnvironmentSetupException(const std::string& message = "Error during handling environment variables") : Exception(message) {} }; struct CredentialSetupException: public Exception { - CredentialSetupException(const std::string& message = "Error during handling environment variables") + explicit CredentialSetupException(const std::string& message = "Error during handling environment variables") : Exception(message) {} }; struct CapabilitySetupException: public Exception { - CapabilitySetupException(const std::string& message = "Error during a capability operation") + explicit CapabilitySetupException(const std::string& message = "Error during a capability operation") : Exception(message) {} }; struct BadArgument: public Exception { - BadArgument(const std::string& message = "Bad argument passed") + explicit BadArgument(const std::string& message = "Bad argument passed") : Exception(message) {} }; struct NoSuchValue: public Exception { - NoSuchValue(const std::string& message = "Value not found") + explicit NoSuchValue(const std::string& message = "Value not found") : Exception(message) {} }; struct NetworkException : public Exception { - NetworkException (const std::string& message = "Error during setting up a network") + explicit NetworkException (const std::string& message = "Error during setting up a network") : Exception(message) {} }; struct ConfigureException: public Exception { - ConfigureException(const std::string& message = "Error while configuring a container") + explicit ConfigureException(const std::string& message = "Error while configuring a container") : Exception(message) {} }; diff --git a/server/exception.hpp b/server/exception.hpp index e1b3be4..e72df76 100644 --- a/server/exception.hpp +++ b/server/exception.hpp @@ -37,7 +37,7 @@ namespace vasum { */ struct ServerException: public VasumException { - ServerException(const std::string& error) : VasumException(error) {} + explicit ServerException(const std::string& error) : VasumException(error) {} }; /** @@ -46,7 +46,7 @@ struct ServerException: public VasumException { */ struct ZoneOperationException: public ServerException { - ZoneOperationException(const std::string& error) : ServerException(error) {} + explicit ZoneOperationException(const std::string& error) : ServerException(error) {} }; /** @@ -54,7 +54,7 @@ struct ZoneOperationException: public ServerException { */ struct InvalidZoneIdException : public ServerException { - InvalidZoneIdException(const std::string& error) : ServerException(error) {} + explicit InvalidZoneIdException(const std::string& error) : ServerException(error) {} }; /** @@ -62,7 +62,7 @@ struct InvalidZoneIdException : public ServerException { */ struct ZoneConnectionException: public ServerException { - ZoneConnectionException(const std::string& error) : ServerException(error) {} + explicit ZoneConnectionException(const std::string& error) : ServerException(error) {} }; /** @@ -70,7 +70,7 @@ struct ZoneConnectionException: public ServerException { */ struct HostConnectionException: public ServerException { - HostConnectionException(const std::string& error) : ServerException(error) {} + explicit HostConnectionException(const std::string& error) : ServerException(error) {} }; /** @@ -79,12 +79,12 @@ struct HostConnectionException: public ServerException { */ struct InputMonitorException: public ServerException { - InputMonitorException(const std::string& error) : ServerException(error) {} + explicit InputMonitorException(const std::string& error) : ServerException(error) {} }; struct TimeoutException: public InputMonitorException { - TimeoutException(const std::string& error) : InputMonitorException (error) {} + explicit TimeoutException(const std::string& error) : InputMonitorException (error) {} }; } diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 55e63f5..baf3ed1 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -1266,7 +1266,7 @@ void ZonesManager::createZone(const std::string& id, } catch (std::runtime_error& e) { LOGE("Generate config failed: " << e.what()); utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr)); - throw e; + throw; } LOGT("Creating new zone"); @@ -1275,7 +1275,7 @@ void ZonesManager::createZone(const std::string& id, } catch (std::runtime_error& e) { LOGE("Creating new zone failed: " << e.what()); utils::launchAsRoot(std::bind(removeAllWrapper, zonePathStr)); - throw e; + throw; } mDynamicConfig.zoneIds.push_back(id); diff --git a/tests/cppcheck/cppcheck.sh b/tests/cppcheck/cppcheck.sh index b8bb637..bbe96b5 100755 --- a/tests/cppcheck/cppcheck.sh +++ b/tests/cppcheck/cppcheck.sh @@ -11,5 +11,7 @@ OPT+=" -I common" OPT+=" -I libs" OPT+=" -I client" OPT+=" -I server" +OPT+=" -I tests/unit_tests" +OPT+=" -I tests/unit_tests/socket_test_service" OPT+=" -U__NR_capset" -cppcheck ${OPT} --template=gcc ./ 1>/dev/null +cppcheck ${OPT} --template=gcc $@ ./ 1>/dev/null diff --git a/tests/cppcheck/cppcheck.suppress b/tests/cppcheck/cppcheck.suppress index d3b098f..8d7380b 100644 --- a/tests/cppcheck/cppcheck.suppress +++ b/tests/cppcheck/cppcheck.suppress @@ -1,7 +1,26 @@ // public API functions (or write tests to use them all) unusedFunction:wrapper/wrapper-compatibility.cpp unusedFunction:wrapper/wrapper.cpp +unusedFunction:libs/config/kvstore.cpp +unusedFunction:libs/ipc/internals/processor.cpp +unusedFunction:server/zones-manager.cpp +unusedFunction:libs/lxcpp/container-impl.cpp +unusedFunction:libs/lxcpp/filesystem.cpp +unusedFunction:libs/lxcpp/network.cpp +unusedFunction:libs/lxcpp/network-config.cpp +unusedFunction:client/vasum-client.cpp +unusedFunction:common/netlink/netlink-message.cpp +unusedFunction:common/utils/fd-utils.cpp +unusedFunction:server/zone.cpp -// lambda not recognized to catch exception (v1.68) -exceptThrowInNoexecptFunction:client/vasum-client-impl.cpp +// lambda not recognized to catch exception (v1.69) +throwInNoexceptFunction:client/vasum-client-impl.cpp +// complains that all constructors with 1 argument should be explicit +noExplicitConstructor + +// required for C abstraction +unusedStructMember:common/utils/initctl.cpp + +// functions called by external utilities +unusedFunction:tests/unit_tests/ut.cpp diff --git a/tests/unit_tests/ipc/ut-ipc.cpp b/tests/unit_tests/ipc/ut-ipc.cpp index 853faa2..5ba540e 100644 --- a/tests/unit_tests/ipc/ut-ipc.cpp +++ b/tests/unit_tests/ipc/ut-ipc.cpp @@ -237,7 +237,7 @@ void testEcho(Client& c, const MethodID methodID) BOOST_CHECK_EQUAL(recvData->intVal, sentData->intVal); } -void testEcho(Service& s, const MethodID methodID, const PeerID peerID) +void testEcho(Service& s, const MethodID methodID, const PeerID& peerID) { std::shared_ptr sentData(new SendData(56)); std::shared_ptr recvData = s.callSync(methodID, peerID, sentData, TIMEOUT); diff --git a/tests/unit_tests/server/ut-zones-manager.cpp b/tests/unit_tests/server/ut-zones-manager.cpp index 819da53..6d6a71d 100644 --- a/tests/unit_tests/server/ut-zones-manager.cpp +++ b/tests/unit_tests/server/ut-zones-manager.cpp @@ -163,7 +163,7 @@ public: void signalSubscribe(const DbusConnection::SignalCallback& callback) { - mClient->signalSubscribe(callback, isHost() ? api::dbus::BUS_NAME : api::dbus::BUS_NAME); + mClient->signalSubscribe(callback, api::dbus::BUS_NAME); } void callSwitchToDefault() @@ -225,12 +225,9 @@ public: interface.c_str(), method.c_str(), parameters); - GVariantPtr result = mClient->callMethod(isHost() ? api::dbus::BUS_NAME : - api::dbus::BUS_NAME, - isHost() ? api::dbus::OBJECT_PATH : - api::dbus::OBJECT_PATH, - isHost() ? api::dbus::INTERFACE : - api::dbus::INTERFACE, + GVariantPtr result = mClient->callMethod(api::dbus::BUS_NAME, + api::dbus::OBJECT_PATH, + api::dbus::INTERFACE, api::dbus::METHOD_PROXY_CALL, packedParameters, "(v)"); diff --git a/tests/unit_tests/utils/ut-worker.cpp b/tests/unit_tests/utils/ut-worker.cpp index 52c14fd..b05aef0 100644 --- a/tests/unit_tests/utils/ut-worker.cpp +++ b/tests/unit_tests/utils/ut-worker.cpp @@ -166,7 +166,7 @@ BOOST_AUTO_TEST_CASE(NoCopy) Task(Task&& r) : count(r.count) {} Task& operator=(const Task&) = delete; Task& operator=(Task&&) = delete; - void operator() () {} + void operator() () const {} }; diff --git a/zone-daemon/exception.hpp b/zone-daemon/exception.hpp index 5fcf54d..9889e62 100644 --- a/zone-daemon/exception.hpp +++ b/zone-daemon/exception.hpp @@ -37,7 +37,7 @@ namespace zone_daemon { */ struct ZoneDaemonException: public VasumException { - ZoneDaemonException(const std::string& error) : VasumException(error) {} + explicit ZoneDaemonException(const std::string& error) : VasumException(error) {} }; -- 2.7.4 From ded590f480be25eb3b8c593187606f9859c942ee Mon Sep 17 00:00:00 2001 From: Pawel Kubik Date: Wed, 9 Sep 2015 17:27:08 +0200 Subject: [PATCH 13/16] Static common library [Feature] Static common library [Cause] Need for cleaner dependency management [Solution] Rules for building static common library, linking it with other binaries instead of manually adding sources [Verification] Build, install, run tests and main executables Change-Id: I6eccf5a706b88ca4576e5bfc31b73ebe87177ff5 --- CMakeLists.txt | 2 +- cli/CMakeLists.txt | 10 ++++------ client/CMakeLists.txt | 9 ++++----- common/CMakeLists.txt | 29 +++++++++++++++++++++++++++++ libs/dbus/CMakeLists.txt | 15 +++++---------- libs/ipc/CMakeLists.txt | 14 +++++--------- libs/logger/CMakeLists.txt | 15 ++++++--------- libs/lxcpp/CMakeLists.txt | 23 ++++++----------------- server/CMakeLists.txt | 8 ++++---- tests/unit_tests/CMakeLists.txt | 21 ++++++++++++--------- wrapper/CMakeLists.txt | 12 ++++-------- zone-daemon/CMakeLists.txt | 7 +++---- 12 files changed, 83 insertions(+), 82 deletions(-) create mode 100644 common/CMakeLists.txt diff --git a/CMakeLists.txt b/CMakeLists.txt index 9823735..5b98eee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,6 +188,7 @@ SET(VSM_CONFIG_INSTALL_DIR ${SYSCONF_INSTALL_DIR}/vasum) SET(VSM_SERVER_IPC_SOCKET_PATH ${RUN_DIR}/vasum.socket) SET(VSM_UNIT_TESTS_IPC_SOCKET_PATH ${RUN_DIR}/vasum-ipc-unit-tests.socket) +ADD_SUBDIRECTORY(${COMMON_FOLDER}) ADD_SUBDIRECTORY(${LOGGER_FOLDER}) ADD_SUBDIRECTORY(${LXCPP_FOLDER}) IF(NOT WITHOUT_DBUS) @@ -204,4 +205,3 @@ ENDIF(NOT WITHOUT_DBUS) ADD_SUBDIRECTORY(${TESTS_FOLDER}) ADD_SUBDIRECTORY(${CLI_FOLDER}) ADD_SUBDIRECTORY(${WRAPPER_FOLDER}) - diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index 0f4fbfe..478cc25 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -19,14 +19,14 @@ MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the command line interface...") -FILE(GLOB cli_SRCS *.cpp *.hpp - ${COMMON_FOLDER}/utils/c-array.cpp - ${COMMON_FOLDER}/utils/c-array.hpp) +FILE(GLOB cli_SRCS *.cpp *.hpp) ## Setup target ################################################################ SET(CLI_CODENAME "vsm") ADD_EXECUTABLE(${CLI_CODENAME} ${cli_SRCS}) +ADD_DEPENDENCIES(${CLI_CODENAME} Common ${PROJECT_NAME}-client Ipc) + ## Readline detection ########################################################## FIND_PATH(READLINE_INCLUDE_DIR readline/readline.h @@ -46,11 +46,9 @@ INCLUDE_DIRECTORIES(${READLINE_INCLUDE_DIRS}) TARGET_LINK_LIBRARIES(${CLI_CODENAME} ${READLINE_LIBRARIES}) ## Link libraries ############################################################## -PKG_CHECK_MODULES(LIB_DEPS REQUIRED vasum) - INCLUDE_DIRECTORIES(${CLIENT_FOLDER}) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) -TARGET_LINK_LIBRARIES(${CLI_CODENAME} ${PROJECT_NAME}-client ${LIB_DEPS_LIBRARIES} Ipc) +TARGET_LINK_LIBRARIES(${CLI_CODENAME} Common ${PROJECT_NAME}-client ${LIB_DEPS_LIBRARIES} Ipc) CONFIGURE_FILE(support/vsm-completion.sh.in ${CMAKE_BINARY_DIR}/vsm-completion.sh diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index f0d1828..e4e9ca5 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -22,9 +22,6 @@ MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the Client...") FILE(GLOB project_SRCS *.cpp *.hpp *.h) -FILE(GLOB common_SRCS ${COMMON_FOLDER}/utils/*.hpp ${COMMON_FOLDER}/utils/*.cpp - ${COMMON_FOLDER}/*.hpp ${COMMON_FOLDER}/*.cpp) - SET(_LIB_VERSION_ "${VERSION}") SET(_LIB_SOVERSION_ "0") SET(PC_FILE "${PROJECT_NAME}.pc") @@ -36,12 +33,14 @@ SET(PC_FILE "${PROJECT_NAME}.pc") ADD_DEFINITIONS(-fvisibility=hidden) ## Setup target ################################################################ -ADD_LIBRARY(${PROJECT_NAME} SHARED ${project_SRCS} ${common_SRCS}) +ADD_LIBRARY(${PROJECT_NAME} SHARED ${project_SRCS}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${_LIB_SOVERSION_} VERSION ${_LIB_VERSION_} COMPILE_DEFINITIONS HOST_IPC_SOCKET="${VSM_SERVER_IPC_SOCKET_PATH}") +ADD_DEPENDENCIES(${PROJECT_NAME} Common Config Ipc) + ## Link libraries ############################################################## FIND_PACKAGE(Boost COMPONENTS system filesystem) PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0) @@ -51,7 +50,7 @@ INCLUDE_DIRECTORIES(${LIBS_FOLDER}) INCLUDE_DIRECTORIES(${IPC_FOLDER}) INCLUDE_DIRECTORIES(${SERVER_FOLDER}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${LIB_DEPS_LIBRARIES} ${Boost_LIBRARIES} Config Ipc) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${LIB_DEPS_LIBRARIES} ${Boost_LIBRARIES} Config Ipc) IF(NOT WITHOUT_DBUS) TARGET_LINK_LIBRARIES(${PROJECT_NAME} SimpleDbus) ENDIF(NOT WITHOUT_DBUS) diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt new file mode 100644 index 0000000..8534a46 --- /dev/null +++ b/common/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# +# @file CMakeLists.txt +# @author Pawel Kubik (p.kubik@samsung.com) +# + +MESSAGE(STATUS "") +MESSAGE(STATUS "Generating makefile for the libCommon...") +FILE(GLOB_RECURSE SRCS *.cpp *.hpp) + +## Setup target ################################################################ +ADD_LIBRARY(Common STATIC ${SRCS}) + +PKG_CHECK_MODULES(COMMON_DEPS REQUIRED glib-2.0) + +INCLUDE_DIRECTORIES(SYSTEM ${COMMON_FOLDER} ${LIBS_FOLDER} ${COMMON_DEPS_INCLUDE_DIRS}) diff --git a/libs/dbus/CMakeLists.txt b/libs/dbus/CMakeLists.txt index 840b3b4..6045c04 100644 --- a/libs/dbus/CMakeLists.txt +++ b/libs/dbus/CMakeLists.txt @@ -22,14 +22,7 @@ PROJECT(SimpleDbus) MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the libSimpleDbus...") FILE(GLOB HEADERS *.hpp) -FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/callback-guard.hpp - ${COMMON_FOLDER}/utils/scoped-gerror.hpp - ${COMMON_FOLDER}/utils/glib-utils.hpp - ${COMMON_FOLDER}/utils/callback-wrapper.hpp) -FILE(GLOB SRCS_UTILS ${COMMON_FOLDER}/utils/callback-guard.cpp - ${COMMON_FOLDER}/utils/scoped-gerror.cpp - ${COMMON_FOLDER}/utils/glib-utils.cpp - ${COMMON_FOLDER}/utils/callback-wrapper.cpp) +FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/callback-guard.hpp) FILE(GLOB SRCS *.cpp *.hpp) SET(_LIB_VERSION_ "${VERSION}") @@ -37,18 +30,20 @@ SET(_LIB_SOVERSION_ "0") SET(PC_FILE "lib${PROJECT_NAME}.pc") ## Setup target ################################################################ -ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_UTILS}) +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${_LIB_SOVERSION_} VERSION ${_LIB_VERSION_} ) +ADD_DEPENDENCIES(${PROJECT_NAME} Common) + ## Link libraries ############################################################## PKG_CHECK_MODULES(DBUS_DEPS REQUIRED glib-2.0 gio-2.0) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(${LIBS_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${DBUS_DEPS_INCLUDE_DIRS}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${DBUS_DEPS_LIBRARIES} Logger) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${pkgs_LDFLAGS} ${DBUS_DEPS_LIBRARIES} Logger) ## Generate the pc file ######################################################## CONFIGURE_FILE(${PC_FILE}.in ${CMAKE_CURRENT_BINARY_DIR}/${PC_FILE} @ONLY) diff --git a/libs/ipc/CMakeLists.txt b/libs/ipc/CMakeLists.txt index 854e0de..9e1e6f9 100644 --- a/libs/ipc/CMakeLists.txt +++ b/libs/ipc/CMakeLists.txt @@ -25,29 +25,25 @@ MESSAGE(STATUS "Generating makefile for the libIpc...") FILE(GLOB HEADERS *.hpp) FILE(GLOB HEADERS_INTERNALS internals/*.hpp) FILE(GLOB HEADERS_EPOLL epoll/*.hpp) -FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/fd-utils.hpp - ${COMMON_FOLDER}/utils/eventfd.hpp - ${COMMON_FOLDER}/utils/exception.hpp +FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/eventfd.hpp ${COMMON_FOLDER}/utils/callback-guard.hpp) FILE(GLOB SRCS *.cpp) FILE(GLOB SRCS_INTERNALS internals/*.cpp) FILE(GLOB SRCS_EPOLL epoll/*.cpp) -FILE(GLOB SRCS_UTILS ${COMMON_FOLDER}/utils/fd-utils.cpp - ${COMMON_FOLDER}/utils/eventfd.cpp - ${COMMON_FOLDER}/utils/exception.cpp - ${COMMON_FOLDER}/utils/callback-guard.cpp) SET(_LIB_VERSION_ "${VERSION}") SET(_LIB_SOVERSION_ "0") SET(PC_FILE "lib${PROJECT_NAME}.pc") ## Setup target ################################################################ -ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_INTERNALS} ${SRCS_UTILS} ${SRCS_EPOLL}) +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_INTERNALS} ${SRCS_EPOLL}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${_LIB_SOVERSION_} VERSION ${_LIB_VERSION_} ) +ADD_DEPENDENCIES(${PROJECT_NAME} Common) + ## Link libraries ############################################################## IF(NOT WITHOUT_SYSTEMD) PKG_CHECK_MODULES(IPC_DEPS REQUIRED libsystemd-daemon uuid) @@ -56,7 +52,7 @@ ENDIF(NOT WITHOUT_SYSTEMD) INCLUDE_DIRECTORIES(${LIBS_FOLDER}) INCLUDE_DIRECTORIES(${COMMON_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${DBUS_DEPS_INCLUDE_DIRS} ${IPC_DEPS_INCLUDE_DIRS} ${CONFIG_DEPS_INCLUDE_DIRS} ${JSON_C_INCLUDE_DIRS}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${IPC_DEPS_LIBRARIES} Logger Config) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${pkgs_LDFLAGS} ${IPC_DEPS_LIBRARIES} Logger Config) ## Generate the pc file ######################################################## CONFIGURE_FILE(${PC_FILE}.in ${CMAKE_CURRENT_BINARY_DIR}/${PC_FILE} @ONLY) diff --git a/libs/logger/CMakeLists.txt b/libs/logger/CMakeLists.txt index 6a65b34..b44a876 100644 --- a/libs/logger/CMakeLists.txt +++ b/libs/logger/CMakeLists.txt @@ -21,22 +21,22 @@ PROJECT(Logger) MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the libLogger...") -FILE(GLOB HEADERS *.hpp) -FILE(GLOB SRCS *.cpp *.hpp) -FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/ccolor.hpp) -FILE(GLOB SRCS_UTILS ${COMMON_FOLDER}/utils/ccolor.cpp) +FILE(GLOB HEADERS *.hpp) +FILE(GLOB SRCS *.cpp *.hpp) SET(_LIB_VERSION_ "${VERSION}") SET(_LIB_SOVERSION_ "0") SET(PC_FILE "lib${PROJECT_NAME}.pc") ## Setup target ################################################################ -ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_UTILS}) +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${_LIB_SOVERSION_} VERSION ${_LIB_VERSION_} ) +ADD_DEPENDENCIES(${PROJECT_NAME} Common) + ## Link libraries ############################################################## IF(NOT WITHOUT_SYSTEMD) PKG_CHECK_MODULES(LOGGER_DEPS REQUIRED libsystemd-journal) @@ -44,7 +44,7 @@ ENDIF(NOT WITHOUT_SYSTEMD) INCLUDE_DIRECTORIES(${LIBS_FOLDER} ${COMMON_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${LOGGER_DEPS_INCLUDE_DIRS}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${LOGGER_DEPS_LIBRARIES}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${pkgs_LDFLAGS} ${LOGGER_DEPS_LIBRARIES}) ## Generate the pc file ######################################################## CONFIGURE_FILE(${PC_FILE}.in ${CMAKE_CURRENT_BINARY_DIR}/${PC_FILE} @ONLY) @@ -59,6 +59,3 @@ INSTALL(TARGETS ${PROJECT_NAME} INSTALL(FILES ${HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/vasum-tools/logger) - -INSTALL(FILES ${HEADERS_UTILS} - DESTINATION ${INCLUDE_INSTALL_DIR}/vasum-tools/logger/utils) diff --git a/libs/lxcpp/CMakeLists.txt b/libs/lxcpp/CMakeLists.txt index c76de74..203ddd3 100644 --- a/libs/lxcpp/CMakeLists.txt +++ b/libs/lxcpp/CMakeLists.txt @@ -21,22 +21,11 @@ PROJECT(lxcpp) MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the liblxcpp...") -FILE(GLOB HEADERS *.hpp) -FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/fd-utils.hpp - ${COMMON_FOLDER}/utils/exception.hpp - ${COMMON_FOLDER}/utils/channel.hpp - ${COMMON_FOLDER}/utils/environment.hpp - ${COMMON_FOLDER}/utils/execute.hpp) -FILE(GLOB HEADERS_NETLINK ${COMMON_FOLDER}/netlink/*.hpp) +FILE(GLOB HEADERS *.hpp) +FILE(GLOB HEADERS_UTILS ${COMMON_FOLDER}/utils/channel.hpp) FILE(GLOB HEADERS_COMMANDS commands/*.hpp) FILE(GLOB SRCS *.cpp *.hpp) -FILE(GLOB SRCS_UTILS ${COMMON_FOLDER}/utils/fd-utils.cpp - ${COMMON_FOLDER}/utils/exception.cpp - ${COMMON_FOLDER}/utils/channel.cpp - ${COMMON_FOLDER}/utils/environment.cpp - ${COMMON_FOLDER}/utils/execute.cpp) -FILE(GLOB SRCS_NETLINK ${COMMON_FOLDER}/netlink/*.cpp) FILE(GLOB SRCS_COMMANDS commands/*.cpp) SET(_LIB_VERSION_ "${VERSION}") @@ -44,17 +33,19 @@ SET(_LIB_SOVERSION_ "0") SET(PC_FILE "lib${PROJECT_NAME}.pc") ## Setup target ################################################################ -ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_UTILS} ${SRCS_NETLINK} ${SRCS_COMMANDS}) +ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_COMMANDS}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${_LIB_SOVERSION_} VERSION ${_LIB_VERSION_} ) +ADD_DEPENDENCIES(${PROJECT_NAME} Common Logger) + ## Link libraries ############################################################## FIND_PACKAGE(Boost COMPONENTS system filesystem) INCLUDE_DIRECTORIES(${LIBS_FOLDER} ${COMMON_FOLDER}) INCLUDE_DIRECTORIES(SYSTEM ${Boost_INCLUDE_DIRS}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${pkgs_LDFLAGS} ${Boost_LIBRARIES} Logger) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${pkgs_LDFLAGS} ${Boost_LIBRARIES} Logger) ## Generate the pc file ######################################################## CONFIGURE_FILE(${PC_FILE}.in ${CMAKE_CURRENT_BINARY_DIR}/${PC_FILE} @ONLY) @@ -71,7 +62,5 @@ INSTALL(FILES ${HEADERS} DESTINATION ${INCLUDE_INSTALL_DIR}/lxcpp) INSTALL(FILES ${HEADERS_UTILS} DESTINATION ${INCLUDE_INSTALL_DIR}/lxcpp/utils) -INSTALL(FILES ${HEADERS_NETLINK} - DESTINATION ${INCLUDE_INSTALL_DIR}/lxcpp/netlink) INSTALL(FILES ${HEADERS_COMMANDS} DESTINATION ${INCLUDE_INSTALL_DIR}/lxcpp/commands) diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index 58c50f6..86b4f79 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -19,14 +19,14 @@ MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the Server...") -FILE(GLOB project_SRCS *.cpp *.hpp) -FILE(GLOB_RECURSE common_SRCS ${COMMON_FOLDER}/*.cpp ${COMMON_FOLDER}/*.hpp) +FILE(GLOB project_SRCS *.cpp *.hpp) ## Setup target ################################################################ SET(SERVER_CODENAME "${PROJECT_NAME}-server") -ADD_EXECUTABLE(${SERVER_CODENAME} ${project_SRCS} ${common_SRCS}) +ADD_EXECUTABLE(${SERVER_CODENAME} ${project_SRCS}) +ADD_DEPENDENCIES(${SERVER_CODENAME} Common Logger Config Ipc) ## Link libraries ############################################################## FIND_PACKAGE(Boost COMPONENTS program_options system filesystem regex) @@ -43,7 +43,7 @@ SET_TARGET_PROPERTIES(${SERVER_CODENAME} PROPERTIES LINK_FLAGS "-pthread" ) -TARGET_LINK_LIBRARIES(${SERVER_CODENAME} ${SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES} Logger Config Ipc) +TARGET_LINK_LIBRARIES(${SERVER_CODENAME} Common ${SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES} Logger Config Ipc) IF(NOT WITHOUT_DBUS) TARGET_LINK_LIBRARIES(${SERVER_CODENAME} SimpleDbus) ENDIF(NOT WITHOUT_DBUS) diff --git a/tests/unit_tests/CMakeLists.txt b/tests/unit_tests/CMakeLists.txt index b532336..1c05576 100644 --- a/tests/unit_tests/CMakeLists.txt +++ b/tests/unit_tests/CMakeLists.txt @@ -20,7 +20,6 @@ MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the Unit Tests...") FILE(GLOB_RECURSE project_SRCS *.cpp *.hpp) -FILE(GLOB_RECURSE common_SRCS ${COMMON_FOLDER}/*.cpp ${COMMON_FOLDER}/*.hpp) FILE(GLOB server_SRCS ${SERVER_FOLDER}/*.cpp ${SERVER_FOLDER}/*.hpp) FILE(GLOB client_SRCS ${CLIENT_FOLDER}/*.cpp ${CLIENT_FOLDER}/*.h) FILE(GLOB socket_test_SRCS ${SOCKET_TEST_FOLDER}/*.cpp ${SOCKET_TEST_FOLDER}/*.hpp) @@ -35,20 +34,25 @@ LIST(REMOVE_ITEM project_SRCS ${socket_test_SRCS} ${lxcpp_test_SRCS}) ## Setup target ################################################################ SET(UT_SERVER_CODENAME "${PROJECT_NAME}-server-unit-tests") -ADD_EXECUTABLE(${UT_SERVER_CODENAME} ${project_SRCS} ${common_SRCS} ${server_SRCS} ${client_SRCS}) +ADD_EXECUTABLE(${UT_SERVER_CODENAME} ${project_SRCS} ${server_SRCS} ${client_SRCS}) +ADD_DEPENDENCIES(${UT_SERVER_CODENAME} ${PROJECT_NAME}-server) ## A fake target to test vasum-client C API -ADD_EXECUTABLE("vasum-client-c-api-compile-test" client/client-c-api-compile-test.c) +SET(CLIENT_C_API_COMPILE_TEST "vasum-client-c-api-compile-test") +ADD_EXECUTABLE(${CLIENT_C_API_COMPILE_TEST} client/client-c-api-compile-test.c) +ADD_DEPENDENCIES(${CLIENT_C_API_COMPILE_TEST} ${PROJECT_NAME}-client) ## A fake target to test lxcpp API -ADD_EXECUTABLE("lxcpp-api-compile-test" lxcpp/lxcpp-api-compile-test.cpp) -TARGET_LINK_LIBRARIES("lxcpp-api-compile-test" lxcpp) +SET(LXCPP_API_COMPILE_TEST "lxcpp-api-compile-test") +ADD_EXECUTABLE(${LXCPP_API_COMPILE_TEST} lxcpp/lxcpp-api-compile-test.cpp) +ADD_DEPENDENCIES(${LXCPP_API_COMPILE_TEST} lxcpp) +TARGET_LINK_LIBRARIES(${LXCPP_API_COMPILE_TEST} lxcpp) IF(NOT WITHOUT_SYSTEMD) SET(SOCKET_TEST_CODENAME "${PROJECT_NAME}-socket-test") ## A stub mini-service to test socket functionality -ADD_EXECUTABLE(${SOCKET_TEST_CODENAME} ${socket_test_SRCS} ${common_SRCS} ${client_SRCS}) +ADD_EXECUTABLE(${SOCKET_TEST_CODENAME} ${socket_test_SRCS} ${client_SRCS}) ENDIF(NOT WITHOUT_SYSTEMD) ## Link libraries ############################################################## @@ -65,7 +69,7 @@ SET_TARGET_PROPERTIES(${UT_SERVER_CODENAME} PROPERTIES LINK_FLAGS "-pthread" ) -TARGET_LINK_LIBRARIES(${UT_SERVER_CODENAME} ${UT_SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES} +TARGET_LINK_LIBRARIES(${UT_SERVER_CODENAME} Common ${UT_SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES} Logger Config Ipc lxcpp) IF(NOT WITHOUT_DBUS) TARGET_LINK_LIBRARIES(${UT_SERVER_CODENAME} SimpleDbus) @@ -78,7 +82,7 @@ SET_TARGET_PROPERTIES(${SOCKET_TEST_CODENAME} PROPERTIES LINK_FLAGS "-pthread" ) -TARGET_LINK_LIBRARIES(${SOCKET_TEST_CODENAME} ${UT_SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES} +TARGET_LINK_LIBRARIES(${SOCKET_TEST_CODENAME} Common ${UT_SERVER_DEPS_LIBRARIES} ${Boost_LIBRARIES} Logger Config Ipc) IF(NOT WITHOUT_DBUS) TARGET_LINK_LIBRARIES(${SOCKET_TEST_CODENAME} SimpleDbus) @@ -100,4 +104,3 @@ INSTALL(TARGETS ${UT_SERVER_CODENAME} DESTINATION bin) IF(NOT WITHOUT_SYSTEMD) INSTALL(TARGETS ${SOCKET_TEST_CODENAME} DESTINATION bin) ENDIF(NOT WITHOUT_SYSTEMD) - diff --git a/wrapper/CMakeLists.txt b/wrapper/CMakeLists.txt index 3346df8..7e70765 100644 --- a/wrapper/CMakeLists.txt +++ b/wrapper/CMakeLists.txt @@ -27,12 +27,6 @@ FILE(GLOB wrapper_SRCS *.cpp *.hpp *.h ${CLIENT_FOLDER}/host-ipc-connection.hpp ${CLIENT_FOLDER}/host-ipc-connection.cpp ${CLIENT_FOLDER}/utils.hpp ${CLIENT_FOLDER}/utils.cpp) -FILE(GLOB common_SRCS ${COMMON_FOLDER}/epoll/*.hpp ${COMMON_FOLDER}/epoll/*.cpp - ${COMMON_FOLDER}/ipc/*.hpp ${COMMON_FOLDER}/ipc/*.cpp - ${COMMON_FOLDER}/ipc/internals/*.hpp ${COMMON_FOLDER}/ipc/internals/*.cpp - ${COMMON_FOLDER}/utils/*.hpp ${COMMON_FOLDER}/utils/*.cpp - ${COMMON_FOLDER}/*.hpp ${COMMON_FOLDER}/*.cpp) - SET(_LIB_VERSION_ "${VERSION}") SET(_LIB_SOVERSION_ "0") SET(PC_FILE "${PROJECT_NAME}.pc") @@ -44,12 +38,14 @@ SET(PC_FILE "${PROJECT_NAME}.pc") ADD_DEFINITIONS(-fvisibility=hidden) ADD_DEFINITIONS(-D__STDC_FORMAT_MACROS) -ADD_LIBRARY(${PROJECT_NAME} SHARED ${wrapper_SRCS} ${common_SRCS}) +ADD_LIBRARY(${PROJECT_NAME} SHARED ${wrapper_SRCS}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${_LIB_SOVERSION_} VERSION ${_LIB_VERSION_} COMPILE_DEFINITIONS HOST_IPC_SOCKET="${VSM_SERVER_IPC_SOCKET_PATH}") +ADD_DEPENDENCIES(${PROJECT_NAME} Common Config Ipc) + ## Link libraries ############################################################## FIND_PACKAGE(Boost COMPONENTS system filesystem) PKG_CHECK_MODULES(LIB_DEPS REQUIRED gio-2.0) @@ -59,7 +55,7 @@ INCLUDE_DIRECTORIES(${LIBS_FOLDER}) INCLUDE_DIRECTORIES(${SERVER_FOLDER}) INCLUDE_DIRECTORIES(${CLIENT_FOLDER}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${LIB_DEPS_LIBRARIES} ${Boost_LIBRARIES} Config Ipc) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${LIB_DEPS_LIBRARIES} ${Boost_LIBRARIES} Config Ipc) IF(NOT WITHOUT_DBUS) TARGET_LINK_LIBRARIES(${PROJECT_NAME} SimpleDbus) ENDIF(NOT WITHOUT_DBUS) diff --git a/zone-daemon/CMakeLists.txt b/zone-daemon/CMakeLists.txt index 7171eee..0437a4f 100644 --- a/zone-daemon/CMakeLists.txt +++ b/zone-daemon/CMakeLists.txt @@ -20,13 +20,12 @@ MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the Zone Daemon...") FILE(GLOB project_SRCS *.cpp *.hpp) -FILE(GLOB common_SRCS ${COMMON_FOLDER}/utils/*.cpp ${COMMON_FOLDER}/utils/*.hpp - ${COMMON_FOLDER}/*.cpp) ## Setup target ################################################################ SET(ZONE_DAEMON_CODENAME "${PROJECT_NAME}-zone-daemon") -ADD_EXECUTABLE(${ZONE_DAEMON_CODENAME} ${project_SRCS} ${common_SRCS}) +ADD_EXECUTABLE(${ZONE_DAEMON_CODENAME} ${project_SRCS}) +ADD_DEPENDENCIES(${ZONE_DAEMON_CODENAME} Common Logger SimpleDbus Ipc) ## Link libraries ############################################################## FIND_PACKAGE (Boost COMPONENTS program_options system filesystem) @@ -42,7 +41,7 @@ SET_TARGET_PROPERTIES(${ZONE_DAEMON_CODENAME} PROPERTIES LINK_FLAGS "-pthread" ) -TARGET_LINK_LIBRARIES(${ZONE_DAEMON_CODENAME} ${ZONE_DAEMON_DEPS_LIBRARIES} +TARGET_LINK_LIBRARIES(${ZONE_DAEMON_CODENAME} Common ${ZONE_DAEMON_DEPS_LIBRARIES} ${Boost_LIBRARIES} Logger SimpleDbus Ipc) -- 2.7.4 From 54a315716b6773507cc0bffa236f10f11c5d2400 Mon Sep 17 00:00:00 2001 From: Pawel Kubik Date: Mon, 14 Sep 2015 12:20:36 +0200 Subject: [PATCH 14/16] CLI bash completion fix [Feature] CLI bash completion fix [Cause] Bash completion broken after commit 4a9c93f [Solution] Bash completion script template fix [Verification] Build, install, check CLI completion Change-Id: Iff043a983d042e4181b33b0f6c4e415befcc22ed --- cli/support/vsm-completion.sh.in | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/cli/support/vsm-completion.sh.in b/cli/support/vsm-completion.sh.in index 74a02a5..704e162 100755 --- a/cli/support/vsm-completion.sh.in +++ b/cli/support/vsm-completion.sh.in @@ -2,8 +2,13 @@ [ -z "$BASH_VERSION" ] && return __@PROJECT_NAME@_cli() { - words=`@CLI_CODENAME@ --bash-completion ${COMP_WORDS[COMP_CWORD]}` - COMPREPLY=($(compgen -W "$words" -- ${COMP_WORDS[COMP_CWORD]})) + if [ "${COMP_WORDS[COMP_CWORD]}" = "" ]; then + comp="''" + else + comp= + fi + words=`@CLI_CODENAME@ --bash-completion $(echo "${COMP_WORDS[@]:1}" | sed 's/ = /=/g') $comp` + COMPREPLY=($(compgen -W "$words" -- "${COMP_WORDS[COMP_CWORD]}")) } complete -F __@PROJECT_NAME@_cli vsm -- 2.7.4 From 3166537b1ec126be9343551b0d7801a89c08e637 Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Wed, 16 Sep 2015 11:22:22 +0200 Subject: [PATCH 15/16] lxcpp: Setting up the control terminal [Feature] Setting up the control terminal in Attach [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I6b1dced4f9a16c04e82b122679f86b90be29d3d1 --- libs/lxcpp/commands/attach.cpp | 51 +++++++++++++++++++++++++++++++++++++++++- libs/lxcpp/commands/attach.hpp | 3 +++ libs/lxcpp/container-impl.cpp | 1 + libs/lxcpp/credentials.hpp | 2 -- 4 files changed, 54 insertions(+), 3 deletions(-) diff --git a/libs/lxcpp/commands/attach.cpp b/libs/lxcpp/commands/attach.cpp index 0ff856e..01a811b 100644 --- a/libs/lxcpp/commands/attach.cpp +++ b/libs/lxcpp/commands/attach.cpp @@ -31,9 +31,13 @@ #include "lxcpp/credentials.hpp" #include "utils/exception.hpp" +#include "utils/fd-utils.hpp" +#include "logger/logger.hpp" #include #include +#include +#include #include @@ -67,6 +71,35 @@ void setupMountPoints() */ } +bool setupControlTTY(const int ttyFD) +{ + if (!::isatty(ttyFD)) { + return false; + } + + if (::setsid() < 0) { + return false; + } + + if (::ioctl(ttyFD, TIOCSCTTY, NULL) < 0) { + return false; + } + + if (::dup2(ttyFD, STDIN_FILENO) < 0) { + return false; + } + + if (::dup2(ttyFD, STDOUT_FILENO) < 0) { + return false; + } + + if (::dup2(ttyFD, STDERR_FILENO) < 0) { + return false; + } + + return true; +} + int execFunction(void* call) { try { @@ -83,6 +116,7 @@ Attach::Attach(lxcpp::ContainerImpl& container, Container::AttachCall& userCall, const uid_t uid, const gid_t gid, + const std::string& ttyPath, const std::vector& supplementaryGids, const int capsToKeep, const std::string& workDirInContainer, @@ -98,10 +132,18 @@ Attach::Attach(lxcpp::ContainerImpl& container, mEnvToKeep(envToKeep), mEnvToSet(envToSet) { + mTTYFD = ::open(ttyPath.c_str(), O_RDWR | O_NOCTTY); + if (mTTYFD < 0) { + const std::string msg = "open() failed: " + + utils::getSystemErrorMessage(); + LOGE(msg); + throw BadArgument(msg); + } } Attach::~Attach() { + utils::close(mTTYFD); } void Attach::execute() @@ -113,6 +155,7 @@ void Attach::execute() mUserCall, mUid, mGid, + mTTYFD, mSupplementaryGids, mCapsToKeep, mEnvToKeep, @@ -127,13 +170,14 @@ void Attach::execute() intermChannel.setRight(); interm(intermChannel, call); intermChannel.shutdown(); - ::_exit(0); + ::_exit(EXIT_SUCCESS); } } int Attach::child(const Container::AttachCall& call, const uid_t uid, const gid_t gid, + const int ttyFD, const std::vector& supplementaryGids, const int capsToKeep, const std::vector& envToKeep, @@ -155,6 +199,11 @@ int Attach::child(const Container::AttachCall& call, lxcpp::setuid(uid); + // Set control TTY + if(!setupControlTTY(ttyFD)) { + ::_exit(EXIT_FAILURE); + } + // Run user's code return call(); } diff --git a/libs/lxcpp/commands/attach.hpp b/libs/lxcpp/commands/attach.hpp index 36c57ba..2c1f365 100644 --- a/libs/lxcpp/commands/attach.hpp +++ b/libs/lxcpp/commands/attach.hpp @@ -58,6 +58,7 @@ public: Container::AttachCall& userCall, const uid_t uid, const gid_t gid, + const std::string& ttyPath, const std::vector& supplementaryGids, const int capsToKeep, const std::string& workDirInContainer, @@ -72,6 +73,7 @@ private: const Container::AttachCall& mUserCall; const uid_t mUid; const gid_t mGid; + int mTTYFD; const std::vector& mSupplementaryGids; const int mCapsToKeep; const std::string& mWorkDirInContainer; @@ -82,6 +84,7 @@ private: static int child(const Container::AttachCall& call, const uid_t uid, const gid_t gid, + const int ttyFD, const std::vector& supplementaryGids, const int capsToKeep, const std::vector& envToKeep, diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp index 73e5254..8249009 100644 --- a/libs/lxcpp/container-impl.cpp +++ b/libs/lxcpp/container-impl.cpp @@ -152,6 +152,7 @@ void ContainerImpl::attach(Container::AttachCall& call, call, /*uid in container*/ 0, /*gid in container*/ 0, + "/dev/tty", /*supplementary gids in container*/ {}, /*capsToKeep*/ 0, cwdInContainer, diff --git a/libs/lxcpp/credentials.hpp b/libs/lxcpp/credentials.hpp index df00ce5..ab1a490 100644 --- a/libs/lxcpp/credentials.hpp +++ b/libs/lxcpp/credentials.hpp @@ -36,8 +36,6 @@ void setgid(const gid_t gid); void setuid(const uid_t uid); - - } // namespace lxcpp #endif // LXCPP_CREDENTIALS_HPP \ No newline at end of file -- 2.7.4 From 61e31300c53fb090f48930f4d4462e6bc9218be1 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Wed, 29 Jul 2015 13:27:25 +0200 Subject: [PATCH 16/16] lxcpp: Initial implementation of the start API call [Feature] Initial implementation of the start API call. [Verification] Build, install, run tests Significant changes related to the start API call: - Start command that daemonizes and execs guard binary - Guard process implementation that execs the container's init Additional changes in this commit supporting the Start API call: - API extension to Channel class, support close on exec and be able to survive (as a FD) exec() call - set close on exec in persistent file logger - new logger helper to setup the logger - add pid to the log format Change-Id: I2d9648e2a861add2aa1bd1d66587bff2a109cc9c --- CMakeLists.txt | 8 +- common/utils/channel.cpp | 55 ++++++++++++- common/utils/channel.hpp | 27 ++++++- libs/logger/backend-persistent-file.hpp | 9 ++- libs/logger/formatter.cpp | 5 +- libs/logger/level.hpp | 2 +- libs/logger/logger.cpp | 38 +++++++++ libs/logger/logger.hpp | 28 ++++++- libs/lxcpp/CMakeLists.txt | 10 ++- libs/lxcpp/commands/attach.cpp | 2 + libs/lxcpp/commands/start.cpp | 135 ++++++++++++++++++++++++++++++++ libs/lxcpp/commands/start.hpp | 66 ++++++++++++++++ libs/lxcpp/container-config.hpp | 111 ++++++++++++++++++++++++++ libs/lxcpp/container-impl.cpp | 12 ++- libs/lxcpp/container-impl.hpp | 28 ++----- libs/lxcpp/container.hpp | 5 ++ libs/lxcpp/exception.hpp | 5 ++ libs/lxcpp/guard/CMakeLists.txt | 37 +++++++++ libs/lxcpp/guard/guard.cpp | 100 +++++++++++++++++++++++ libs/lxcpp/guard/guard.hpp | 39 +++++++++ libs/lxcpp/guard/main.cpp | 49 ++++++++++++ libs/lxcpp/logger-config.cpp | 48 ++++++++++++ libs/lxcpp/logger-config.hpp | 65 +++++++++++++++ libs/lxcpp/utils.cpp | 122 +++++++++++++++++++++++++++++ libs/lxcpp/utils.hpp | 54 +++++++++++++ packaging/vasum.spec | 1 + 26 files changed, 1022 insertions(+), 39 deletions(-) create mode 100644 libs/lxcpp/commands/start.cpp create mode 100644 libs/lxcpp/commands/start.hpp create mode 100644 libs/lxcpp/container-config.hpp create mode 100644 libs/lxcpp/guard/CMakeLists.txt create mode 100644 libs/lxcpp/guard/guard.cpp create mode 100644 libs/lxcpp/guard/guard.hpp create mode 100644 libs/lxcpp/guard/main.cpp create mode 100644 libs/lxcpp/logger-config.cpp create mode 100644 libs/lxcpp/logger-config.hpp create mode 100644 libs/lxcpp/utils.cpp create mode 100644 libs/lxcpp/utils.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 5b98eee..0409167 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -143,10 +143,10 @@ ENDIF(NOT DEFINED PYTHON_SITELIB) SET(COMMON_FOLDER ${PROJECT_SOURCE_DIR}/common) SET(LIBS_FOLDER ${PROJECT_SOURCE_DIR}/libs) SET(LOGGER_FOLDER ${PROJECT_SOURCE_DIR}/libs/logger) -SET(LXCPP_FOLDER ${PROJECT_SOURCE_DIR}/libs/lxcpp) SET(DBUS_FOLDER ${PROJECT_SOURCE_DIR}/libs/dbus) SET(CONFIG_FOLDER ${PROJECT_SOURCE_DIR}/libs/config) SET(IPC_FOLDER ${PROJECT_SOURCE_DIR}/libs/ipc) +SET(LXCPP_FOLDER ${PROJECT_SOURCE_DIR}/libs/lxcpp) SET(CLIENT_FOLDER ${PROJECT_SOURCE_DIR}/client) SET(SERVER_FOLDER ${PROJECT_SOURCE_DIR}/server) SET(ZONE_SUPPORT_FOLDER ${PROJECT_SOURCE_DIR}/zone-support) @@ -180,6 +180,10 @@ IF(NOT DEFINED DATA_DIR) SET(DATA_DIR "${CMAKE_INSTALL_PREFIX}/share") ENDIF(NOT DEFINED DATA_DIR) +IF(NOT DEFINED LIBEXEC_DIR) + SET(LIBEXEC_DIR "${CMAKE_INSTALL_PREFIX}/libexec") +ENDIF(NOT DEFINED LIBEXEC_DIR) + IF(NOT DEFINED RUN_DIR) SET(RUN_DIR "/var/run") ENDIF(NOT DEFINED RUN_DIR) @@ -190,12 +194,12 @@ SET(VSM_UNIT_TESTS_IPC_SOCKET_PATH ${RUN_DIR}/vasum-ipc-unit-tests.socket) ADD_SUBDIRECTORY(${COMMON_FOLDER}) ADD_SUBDIRECTORY(${LOGGER_FOLDER}) -ADD_SUBDIRECTORY(${LXCPP_FOLDER}) IF(NOT WITHOUT_DBUS) ADD_SUBDIRECTORY(${DBUS_FOLDER}) ENDIF(NOT WITHOUT_DBUS) ADD_SUBDIRECTORY(${CONFIG_FOLDER}) ADD_SUBDIRECTORY(${IPC_FOLDER}) +ADD_SUBDIRECTORY(${LXCPP_FOLDER}) ADD_SUBDIRECTORY(${CLIENT_FOLDER}) ADD_SUBDIRECTORY(${SERVER_FOLDER}) IF(NOT WITHOUT_DBUS) diff --git a/common/utils/channel.cpp b/common/utils/channel.cpp index fbb110d..3a0dd31 100644 --- a/common/utils/channel.cpp +++ b/common/utils/channel.cpp @@ -27,6 +27,8 @@ #include "logger/logger.hpp" +#include +#include #include namespace { @@ -36,10 +38,15 @@ const int RIGHT = 1; namespace utils { -Channel::Channel() +Channel::Channel(const bool closeOnExec) : mSocketIndex(-1) { - if (::socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, mSockets) < 0) { + int flags = SOCK_STREAM; + if (closeOnExec) { + flags |= SOCK_CLOEXEC; + }; + + if (::socketpair(AF_LOCAL, flags, 0, mSockets.data()) < 0) { const std::string msg = "socketpair() failed: " + utils::getSystemErrorMessage(); LOGE(msg); @@ -47,23 +54,36 @@ Channel::Channel() } } +Channel::Channel(const int fd) + : mSocketIndex(LEFT), + mSockets{{fd, -1}} +{ + assert(fd >= 0); +} + Channel::~Channel() { closeSocket(LEFT); closeSocket(RIGHT); } +/* + * This function has to be safe in regard to signal(7) + */ void Channel::setLeft() { mSocketIndex = LEFT; - utils::close(mSockets[RIGHT]); + ::close(mSockets[RIGHT]); mSockets[RIGHT] = -1; } +/* + * This function has to be safe in regard to signal(7) + */ void Channel::setRight() { mSocketIndex = RIGHT; - utils::close(mSockets[LEFT]); + ::close(mSockets[LEFT]); mSockets[LEFT] = -1; } @@ -73,6 +93,33 @@ void Channel::shutdown() closeSocket(mSocketIndex); } +int Channel::getFD() +{ + assert(mSocketIndex != -1 && "Channel's end isn't set"); + return mSockets[mSocketIndex]; +} + +int Channel::getLeftFD() +{ + return mSockets[LEFT]; +} + +int Channel::getRightFD() +{ + return mSockets[RIGHT]; +} + +void Channel::setCloseOnExec(const bool closeOnExec) +{ + const int fd = getFD(); + + if (closeOnExec) { + ::fcntl(fd, F_SETFD, ::fcntl(fd, F_GETFD) | FD_CLOEXEC); + } else { + ::fcntl(fd, F_SETFD, ::fcntl(fd, F_GETFD) & ~FD_CLOEXEC); + } +} + void Channel::closeSocket(int socketIndex) { utils::shutdown(mSockets[socketIndex]); diff --git a/common/utils/channel.hpp b/common/utils/channel.hpp index f537121..3b60daa 100644 --- a/common/utils/channel.hpp +++ b/common/utils/channel.hpp @@ -26,6 +26,8 @@ #define COMMON_UTILS_CHANNEL_HPP #include "utils/fd-utils.hpp" + +#include #include namespace utils { @@ -35,7 +37,8 @@ namespace utils { */ class Channel { public: - Channel(); + explicit Channel(const bool closeOnExec = true); + explicit Channel(const int fd); ~Channel(); Channel(const Channel&) = delete; @@ -72,12 +75,32 @@ public: template Data read(); + /** + * Get an active file descriptor + */ + int getFD(); + + /** + * Gen the left file descriptor + */ + int getLeftFD(); + + /** + * Gen the right file descriptor + */ + int getRightFD(); + + /** + * Sets close on exec on an active fd to either true or false + */ + void setCloseOnExec(const bool closeOnExec); + private: void closeSocket(int socketIndex); int mSocketIndex; - int mSockets[2]; + std::array mSockets; }; template diff --git a/libs/logger/backend-persistent-file.hpp b/libs/logger/backend-persistent-file.hpp index 74d2def..5cbd714 100644 --- a/libs/logger/backend-persistent-file.hpp +++ b/libs/logger/backend-persistent-file.hpp @@ -27,7 +27,9 @@ #include "logger/backend.hpp" +#include #include +#include namespace logger { @@ -35,7 +37,12 @@ class PersistentFileBackend : public LogBackend { public: PersistentFileBackend(const std::string& filePath) : mfilePath(filePath), - mOut(mfilePath, std::ios::app) {} + mOut(mfilePath, std::ios::app) + { + using filebufType = __gnu_cxx::stdio_filebuf; + const int fd = static_cast(mOut.rdbuf())->fd(); + ::fcntl(fd, F_SETFD, ::fcntl(fd, F_GETFD) | FD_CLOEXEC); + } void log(LogLevel logLevel, const std::string& file, diff --git a/libs/logger/formatter.cpp b/libs/logger/formatter.cpp index 17bed53..06404f2 100644 --- a/libs/logger/formatter.cpp +++ b/libs/logger/formatter.cpp @@ -26,6 +26,7 @@ #include "logger/formatter.hpp" #include "utils/ccolor.hpp" +#include #include #include #include @@ -39,7 +40,7 @@ namespace { const int TIME_COLUMN_LENGTH = 12; const int SEVERITY_COLUMN_LENGTH = 8; -const int THREAD_COLUMN_LENGTH = 3; +const int PROCESS_COLUMN_LENGTH = 8; const int FILE_COLUMN_LENGTH = 60; std::atomic gNextThreadId(1); @@ -122,7 +123,7 @@ std::string LogFormatter::getHeader(LogLevel logLevel, std::ostringstream logLine; logLine << getCurrentTime() << ' ' << std::left << std::setw(SEVERITY_COLUMN_LENGTH) << '[' + toString(logLevel) + ']' - << std::right << std::setw(THREAD_COLUMN_LENGTH) << getCurrentThread() << ": " + << std::right << std::setw(PROCESS_COLUMN_LENGTH) << ::getpid() << "/" << getCurrentThread() << ": " << std::left << std::setw(FILE_COLUMN_LENGTH) << file + ':' + std::to_string(line) + ' ' + func + ':'; return logLine.str(); diff --git a/libs/logger/level.hpp b/libs/logger/level.hpp index fd33343..99dc235 100644 --- a/libs/logger/level.hpp +++ b/libs/logger/level.hpp @@ -33,7 +33,7 @@ namespace logger { * @brief Available log levels * @ingroup libLogger */ -enum class LogLevel { +enum class LogLevel : int { TRACE, ///< Most detailed log level DEBUG, ///< Debug logs INFO, ///< Information diff --git a/libs/logger/logger.cpp b/libs/logger/logger.cpp index ec0855b..fbb85d6 100644 --- a/libs/logger/logger.cpp +++ b/libs/logger/logger.cpp @@ -40,6 +40,44 @@ std::mutex gLogMutex; } // namespace +void setupLogger(const LogType type, + const LogLevel level, + const std::string &arg) +{ + if (type == LogType::LOG_FILE || type == LogType::LOG_PERSISTENT_FILE) { + if (arg.empty()) { + throw std::runtime_error("Path needs to be specified in the agument"); + } + } + + switch(type) { + case LogType::LOG_NULL: + Logger::setLogBackend(new NullLogger()); + break; +#ifdef HAVE_SYSTEMD + case LogType::LOG_JOURNALD: + Logger::setLogBackend(new SystemdJournalBackend()); + break; +#endif + case LogType::LOG_FILE: + Logger::setLogBackend(new FileBackend(arg)); + break; + case LogType::LOG_PERSISTENT_FILE: + Logger::setLogBackend(new PersistentFileBackend(arg)); + break; + case LogType::LOG_SYSLOG: + Logger::setLogBackend(new SyslogBackend()); + break; + case LogType::LOG_STDERR: + Logger::setLogBackend(new StderrBackend()); + break; + default: + throw std::runtime_error("Bad logger type passed"); + } + + Logger::setLogLevel(level); +} + void Logger::logMessage(LogLevel logLevel, const std::string& message, const std::string& file, diff --git a/libs/logger/logger.hpp b/libs/logger/logger.hpp index 0a1ebe6..92baee1 100644 --- a/libs/logger/logger.hpp +++ b/libs/logger/logger.hpp @@ -61,9 +61,14 @@ #define COMMON_LOGGER_LOGGER_HPP #include "logger/level.hpp" +#include "logger/backend-null.hpp" +#ifdef HAVE_SYSTEMD +#include "logger/backend-journal.hpp" +#endif #include "logger/backend-file.hpp" -#include "logger/backend-stderr.hpp" #include "logger/backend-persistent-file.hpp" +#include "logger/backend-syslog.hpp" +#include "logger/backend-stderr.hpp" #include #include @@ -74,6 +79,27 @@ namespace logger { +enum class LogType : int { + LOG_NULL, + LOG_JOURNALD, + LOG_FILE, + LOG_PERSISTENT_FILE, + LOG_SYSLOG, + LOG_STDERR +}; + +/** + * A helper function to easily and completely setup a new logger + * + * @param type logger type to be set up + * @param level maximum log level that will be logged + * @param arg an argument used by some loggers, specific to them + * (e.g. file name for file loggers) + */ +void setupLogger(const LogType type, + const LogLevel level, + const std::string &arg = ""); + class LogBackend; class Logger { diff --git a/libs/lxcpp/CMakeLists.txt b/libs/lxcpp/CMakeLists.txt index 203ddd3..8f391e8 100644 --- a/libs/lxcpp/CMakeLists.txt +++ b/libs/lxcpp/CMakeLists.txt @@ -19,6 +19,9 @@ PROJECT(lxcpp) +SET(GUARD_CODENAME "${PROJECT_NAME}-guard") +ADD_SUBDIRECTORY(guard) + MESSAGE(STATUS "") MESSAGE(STATUS "Generating makefile for the liblxcpp...") FILE(GLOB HEADERS *.hpp) @@ -37,15 +40,18 @@ ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRCS} ${SRCS_COMMANDS}) SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES SOVERSION ${_LIB_SOVERSION_} VERSION ${_LIB_VERSION_} + COMPILE_DEFINITIONS GUARD_PATH="${LIBEXEC_DIR}/${GUARD_CODENAME}" ) ADD_DEPENDENCIES(${PROJECT_NAME} Common Logger) ## Link libraries ############################################################## FIND_PACKAGE(Boost COMPONENTS system filesystem) +PKG_CHECK_MODULES(LXCPP_DEPS REQUIRED glib-2.0) + INCLUDE_DIRECTORIES(${LIBS_FOLDER} ${COMMON_FOLDER}) -INCLUDE_DIRECTORIES(SYSTEM ${Boost_INCLUDE_DIRS}) -TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${pkgs_LDFLAGS} ${Boost_LIBRARIES} Logger) +INCLUDE_DIRECTORIES(SYSTEM ${Boost_INCLUDE_DIRS} ${LXCPP_DEPS_INCLUDE_DIRS} ${JSON_C_INCLUDE_DIRS}) +TARGET_LINK_LIBRARIES(${PROJECT_NAME} Common ${pkgs_LDFLAGS} ${Boost_LIBRARIES} Logger Config) ## Generate the pc file ######################################################## CONFIGURE_FILE(${PC_FILE}.in ${CMAKE_CURRENT_BINARY_DIR}/${PC_FILE} @ONLY) diff --git a/libs/lxcpp/commands/attach.cpp b/libs/lxcpp/commands/attach.cpp index 01a811b..419f651 100644 --- a/libs/lxcpp/commands/attach.cpp +++ b/libs/lxcpp/commands/attach.cpp @@ -167,6 +167,8 @@ void Attach::execute() parent(intermChannel, interPid); intermChannel.shutdown(); } else { + // TODO: only safe functions mentioned in signal(7) should be used below. + // This is not the case now, needs fixing. intermChannel.setRight(); interm(intermChannel, call); intermChannel.shutdown(); diff --git a/libs/lxcpp/commands/start.cpp b/libs/lxcpp/commands/start.cpp new file mode 100644 index 0000000..f68654a --- /dev/null +++ b/libs/lxcpp/commands/start.cpp @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Lukasz Pawelczyk (l.pawelczyk@samsung.com) + * @brief Implementation of starting a container + */ + +#include "lxcpp/commands/start.hpp" +#include "lxcpp/exception.hpp" +#include "lxcpp/process.hpp" +#include "lxcpp/utils.hpp" + +#include "logger/logger.hpp" +#include "config/manager.hpp" + +#include + + +namespace lxcpp { + + +Start::Start(ContainerConfig &config) + : mConfig(config), + mChannel(false), + mGuardPath(GUARD_PATH), + mChannelFD(std::to_string(mChannel.getRightFD())) +{ +} + +Start::~Start() +{ +} + +void Start::execute() +{ + LOGD("Forking daemonize and guard processes. Execing guard libexec binary."); + LOGD("Logging will cease now. It should be restored using some new facility in the guard process."); + const pid_t pid = lxcpp::fork(); + + if (pid > 0) { + mChannel.setLeft(); + parent(pid); + } else { + // Below this point only safe functions mentioned in signal(7) are allowed. + mChannel.setRight(); + daemonize(); + ::_exit(EXIT_FAILURE); + } +} + +void Start::parent(const pid_t pid) +{ + int status = lxcpp::waitpid(pid); + if (status != EXIT_SUCCESS) { + const std::string msg = "Problem with a daemonize process"; + LOGE(msg); + throw ProcessSetupException(msg); + } + + // Send the config to the guard process + config::saveToFD(mChannel.getFD(), mConfig); + + // Read the pids from the guard process + mConfig.mGuardPid = mChannel.read(); + mConfig.mInitPid = mChannel.read(); + + mChannel.shutdown(); + + if (mConfig.mGuardPid <= 0 || mConfig.mInitPid <= 0) { + const std::string msg = "Problem with receiving pids"; + LOGE(msg); + throw ProcessSetupException(msg); + } + + LOGD("Guard PID: " << mConfig.mGuardPid); + LOGD("Init PID: " << mConfig.mInitPid); +} + +void Start::daemonize() +{ + // Double fork() with exit() to reattach the process under the host's init + pid_t pid = ::fork(); + if (pid < 0) { + ::_exit(EXIT_FAILURE); + } + + if (pid == 0) { + // Prepare a clean environment for a guard process: + // - chdir to / so it's independent on other directories + // - null std* fds so it's properly dettached from the terminal + // - set a new session so it cannot reacquire a terminal + + if (::chdir("/") < 0) { + ::_exit(EXIT_FAILURE); + } + if (nullStdFDs() <0) { + ::_exit(EXIT_FAILURE); + } + if (::setsid() < 0) { + ::_exit(EXIT_FAILURE); + } + + // Add name and path of the container to argv. They are not used, but will + // identify the container in the process list in case setProcTitle() fails + // and will guarantee we have enough argv memory to write the title we want. + const char *argv[] = {mGuardPath.c_str(), + mChannelFD.c_str(), + mConfig.mName.c_str(), + mConfig.mRootPath.c_str(), + NULL}; + ::execve(argv[0], const_cast(argv), NULL); + ::_exit(EXIT_FAILURE); + } + + ::_exit(EXIT_SUCCESS); +} + + +} // namespace lxcpp diff --git a/libs/lxcpp/commands/start.hpp b/libs/lxcpp/commands/start.hpp new file mode 100644 index 0000000..758b471 --- /dev/null +++ b/libs/lxcpp/commands/start.hpp @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Lukasz Pawelczyk (l.pawelczyk@samsung.com) + * @brief Headers for starting a container + */ + +#ifndef LXCPP_COMMANDS_START_HPP +#define LXCPP_COMMANDS_START_HPP + +#include "lxcpp/commands/command.hpp" +#include "lxcpp/container-config.hpp" +#include "utils/channel.hpp" + +#include + + +namespace lxcpp { + + +class Start final: Command { +public: + /** + * Starts the container + * + * In more details it prepares an environment for a guard process, + * starts it, and passes it the configuration through a file descriptor. + * + * @param config container's config + */ + Start(ContainerConfig &config); + ~Start(); + + void execute(); + +private: + ContainerConfig &mConfig; + utils::Channel mChannel; + std::string mGuardPath; + std::string mChannelFD; + + void parent(const pid_t pid); + void daemonize(); +}; + + +} // namespace lxcpp + + +#endif // LXCPP_COMMANDS_START_HPP diff --git a/libs/lxcpp/container-config.hpp b/libs/lxcpp/container-config.hpp new file mode 100644 index 0000000..9caad96 --- /dev/null +++ b/libs/lxcpp/container-config.hpp @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Lukasz Pawelczyk (l.pawelczyk@samsung.com) + * @brief A definition of a ContainerConfig struct + */ + +#ifndef LXCPP_CONTAINER_CONFIG_HPP +#define LXCPP_CONTAINER_CONFIG_HPP + +#include "lxcpp/logger-config.hpp" + +#include +#include + +#include +#include +#include + + +namespace lxcpp { + + +struct ContainerConfig { + /** + * Name of the container. + * + * Set: by constructor, cannot be changed afterwards. + * Get: getName() + */ + std::string mName; + + /** + * Path of the root directory of the container. + * + * Set: by contstructor, cannot be changed afterwards. + * Get: getRootPath() + */ + std::string mRootPath; + + /** + * Pid of the guard process. + * + * Set: automatically by the guard process itself. + * Get: getGuardPid() + */ + pid_t mGuardPid; + + /** + * Pid of the container's init process. + * + * Set: automatically by the guard process. + * Get: getInitPid() + */ + pid_t mInitPid; + + /** + * Argv of the container's init process to be executed. + * The path has to be relative to the RootPath. + * + * Set: setInit() + * Get: getInit() + */ + std::vector mInit; + + /** + * Logger to be configured inside the guard process. This logger + * reconfiguration is due to the fact that guard looses standard file + * descriptors and might loose access to other files by mount namespace + * usage. Hence an option to set some other logger that will work + * regardless. E.g. PersistentFile. + * + * Set: setLogger() + * Get: none + */ + LoggerConfig mLogger; + + ContainerConfig() : mGuardPid(-1), mInitPid(-1) {} + + CONFIG_REGISTER + ( + mName, + mRootPath, + mGuardPid, + mInitPid, + mInit, + mLogger + ) +}; + + +} + + +#endif // LXCPP_CONTAINER_CONFIG_HPP diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp index 8249009..cee6fa4 100644 --- a/libs/lxcpp/container-impl.cpp +++ b/libs/lxcpp/container-impl.cpp @@ -28,6 +28,7 @@ #include "lxcpp/namespace.hpp" #include "lxcpp/capability.hpp" #include "lxcpp/commands/attach.hpp" +#include "lxcpp/commands/start.hpp" #include "logger/logger.hpp" #include "utils/exception.hpp" @@ -120,9 +121,18 @@ pid_t ContainerImpl::getInitPid() const return mConfig.mInitPid; } +void ContainerImpl::setLogger(const logger::LogType type, + const logger::LogLevel level, + const std::string &arg) +{ + mConfig.mLogger.set(type, level, arg); +} + void ContainerImpl::start() { - throw NotImplementedException(); + // TODO: check config consistency and completeness somehow + Start start(mConfig); + start.execute(); } void ContainerImpl::stop() diff --git a/libs/lxcpp/container-impl.hpp b/libs/lxcpp/container-impl.hpp index 5435d49..1bf44b7 100644 --- a/libs/lxcpp/container-impl.hpp +++ b/libs/lxcpp/container-impl.hpp @@ -25,37 +25,15 @@ #define LXCPP_CONTAINER_IMPL_HPP #include -#include -#include #include +#include "lxcpp/container-config.hpp" #include "lxcpp/container.hpp" #include "lxcpp/namespace.hpp" #include "lxcpp/network.hpp" -#include "utils/channel.hpp" - namespace lxcpp { -struct ContainerConfig { - std::string mName; - std::string mRootPath; - pid_t mGuardPid; - pid_t mInitPid; - std::vector mInit; - - ContainerConfig() : mGuardPid(-1), mInitPid(-1) {} - - CONFIG_REGISTER - ( - mName, - mRootPath, - mGuardPid, - mInitPid, - mInit - ) -}; - class ContainerImpl : public virtual Container { public: @@ -73,6 +51,10 @@ public: const std::vector& getInit(); void setInit(const std::vector &init); + void setLogger(const logger::LogType type, + const logger::LogLevel level, + const std::string &arg); + const std::vector& getNamespaces() const; // Execution actions diff --git a/libs/lxcpp/container.hpp b/libs/lxcpp/container.hpp index 192f2df..88c3ff8 100644 --- a/libs/lxcpp/container.hpp +++ b/libs/lxcpp/container.hpp @@ -25,6 +25,7 @@ #define LXCPP_CONTAINER_HPP #include "lxcpp/network-config.hpp" +#include "lxcpp/logger-config.hpp" #include #include @@ -60,6 +61,10 @@ public: virtual const std::vector& getInit() = 0; virtual void setInit(const std::vector &init) = 0; + virtual void setLogger(const logger::LogType type, + const logger::LogLevel level, + const std::string &arg) = 0; + // Execution actions virtual void start() = 0; virtual void stop() = 0; diff --git a/libs/lxcpp/exception.hpp b/libs/lxcpp/exception.hpp index 7764282..11a6a0e 100644 --- a/libs/lxcpp/exception.hpp +++ b/libs/lxcpp/exception.hpp @@ -66,6 +66,11 @@ struct CapabilitySetupException: public Exception { : Exception(message) {} }; +struct UtilityException: public Exception { + explicit UtilityException(const std::string& message = "Error during an utility operation") + : Exception(message) {} +}; + struct BadArgument: public Exception { explicit BadArgument(const std::string& message = "Bad argument passed") : Exception(message) {} diff --git a/libs/lxcpp/guard/CMakeLists.txt b/libs/lxcpp/guard/CMakeLists.txt new file mode 100644 index 0000000..6c69300 --- /dev/null +++ b/libs/lxcpp/guard/CMakeLists.txt @@ -0,0 +1,37 @@ +# Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License version 2.1 as published by the Free Software Foundation. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA +# +# @file CMakeLists.txt +# @author Lukasz Pawelczyk (l.pawelczyk@samsung.com) +# + +MESSAGE(STATUS "") +MESSAGE(STATUS "Generating makefile for the Guard...") +FILE(GLOB guard_SRCS *.cpp *.hpp) + + +## Setup target ################################################################ +ADD_EXECUTABLE(${GUARD_CODENAME} ${guard_SRCS}) + + +## Link libraries ############################################################## +PKG_CHECK_MODULES(GUARD_DEPS REQUIRED glib-2.0) +INCLUDE_DIRECTORIES(${LIBS_FOLDER} ${COMMON_FOLDER}) +INCLUDE_DIRECTORIES(SYSTEM ${GUARD_DEPS_INCLUDE_DIRS} ${JSON_C_INCLUDE_DIRS}) +TARGET_LINK_LIBRARIES(${GUARD_CODENAME} lxcpp) + + +## Install ##################################################################### +INSTALL(TARGETS ${GUARD_CODENAME} DESTINATION ${LIBEXEC_DIR}) diff --git a/libs/lxcpp/guard/guard.cpp b/libs/lxcpp/guard/guard.cpp new file mode 100644 index 0000000..63c7263 --- /dev/null +++ b/libs/lxcpp/guard/guard.cpp @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Lukasz Pawelczyk (l.pawelczyk@samsung.com) + * @brief LXCPP guard process implementation + */ + +#include "lxcpp/utils.hpp" +#include "lxcpp/guard/guard.hpp" +#include "lxcpp/process.hpp" + +#include "config/manager.hpp" +#include "logger/logger.hpp" + +#include +#include + + +namespace lxcpp { + + +void startContainer(const ContainerConfig &cfg) +{ + std::vector argv; + argv.reserve(cfg.mInit.size() + 1); + for (auto const & it : cfg.mInit) { + argv.push_back(it.c_str()); + } + argv.push_back(nullptr); + + LOGD("Executing container's init: " << argv[0]); + ::execve(argv[0], const_cast(argv.data()), NULL); + ::_exit(EXIT_FAILURE); +} + +int startGuard(int channelFD) +{ + ContainerConfig cfg; + utils::Channel channel(channelFD); + channel.setCloseOnExec(true); + config::loadFromFD(channel.getFD(), cfg); + + logger::setupLogger(cfg.mLogger.getType(), + cfg.mLogger.getLevel(), + cfg.mLogger.getArg()); + + LOGD("Guard started, config & logging restored"); + + try { + LOGD("Setting the guard process title"); + const std::string title = "[LXCPP] " + cfg.mName + " " + cfg.mRootPath; + setProcTitle(title); + } catch (std::exception &e) { + // Ignore, this is optional + LOGW("Failed to set the guard process title"); + } + + // TODO: container preparation part 1 + + // TODO: switch to clone + LOGD("Forking container's init process"); + pid_t pid = lxcpp::fork(); + + if (pid == 0) { + // TODO: container preparation part 2 + + startContainer(cfg); + ::_exit(EXIT_FAILURE); + } + + cfg.mGuardPid = ::getpid(); + cfg.mInitPid = pid; + + channel.write(cfg.mGuardPid); + channel.write(cfg.mInitPid); + channel.shutdown(); + + int status = lxcpp::waitpid(pid); + LOGD("Init exited with status: " << status); + return status; +} + + +} // namespace lxcpp diff --git a/libs/lxcpp/guard/guard.hpp b/libs/lxcpp/guard/guard.hpp new file mode 100644 index 0000000..78457ae --- /dev/null +++ b/libs/lxcpp/guard/guard.hpp @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Lukasz Pawelczyk (l.pawelczyk@samsung.com) + * @brief LXCPP guard process header + */ + +#ifndef LXCPP_GUARD_GUARD_HPP +#define LXCPP_GUARD_GUARD_HPP + + +#include "lxcpp/container-config.hpp" +#include "utils/channel.hpp" + +namespace lxcpp { + + +int startGuard(int channelFD); + + +} // namespace lxcpp + +#endif // LXCPP_GUARD_HPP diff --git a/libs/lxcpp/guard/main.cpp b/libs/lxcpp/guard/main.cpp new file mode 100644 index 0000000..c8db30b --- /dev/null +++ b/libs/lxcpp/guard/main.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Lukasz Pawelczyk (l.pawelczyk@samsung.com) + * @brief Main file for the Guard process (libexec) + */ + +#include "lxcpp/guard/guard.hpp" + +#include "utils/fd-utils.hpp" + +#include +#include + +int main(int argc, char *argv[]) +{ + if (argc == 1) { + std::cout << "This file should not be executed by hand" << std::endl; + ::_exit(EXIT_FAILURE); + } + + // NOTE: this might not be required now, but I leave it here not to forget. + // We need to investigate this with vasum and think about possibility of + // poorly written software that leaks file descriptors and might use LXCPP. +#if 0 + for(int fd = 3; fd < ::sysconf(_SC_OPEN_MAX); ++fd) { + utils::close(fd); + } +#endif + + int fd = std::stoi(argv[1]); + return lxcpp::startGuard(fd); +} diff --git a/libs/lxcpp/logger-config.cpp b/libs/lxcpp/logger-config.cpp new file mode 100644 index 0000000..3aed302 --- /dev/null +++ b/libs/lxcpp/logger-config.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Lukasz Pawelczyk (l.pawelczyk@samsumg.com) + * @brief Logger configuration + */ + +#include "lxcpp/logger-config.hpp" +#include "lxcpp/exception.hpp" + +namespace lxcpp { + + +void LoggerConfig::set(const logger::LogType type, + const logger::LogLevel level, + const std::string &arg) +{ + if (type == logger::LogType::LOG_FILE || type == logger::LogType::LOG_PERSISTENT_FILE) { + if (arg.empty()) { + const std::string msg = "Path needs to be specified in the agument"; + LOGE(msg); + throw BadArgument(msg); + } + } + + mType = static_cast(type); + mLevel = static_cast(level); + mArg = arg; +} + + +} //namespace lxcpp diff --git a/libs/lxcpp/logger-config.hpp b/libs/lxcpp/logger-config.hpp new file mode 100644 index 0000000..8312623 --- /dev/null +++ b/libs/lxcpp/logger-config.hpp @@ -0,0 +1,65 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Lukasz Pawelczyk (l.pawelczyk@samsumg.com) + * @brief Logger configuration + */ + +#ifndef LXCPP_LOGGER_CONFIG_HPP +#define LXCPP_LOGGER_CONFIG_HPP + +#include "config/config.hpp" +#include "config/fields.hpp" +#include "logger/logger.hpp" + + +namespace lxcpp { + + +/** + * Logger configuration + */ +struct LoggerConfig { +private: + int mType; + int mLevel; + std::string mArg; + +public: + void set(const logger::LogType type, + const logger::LogLevel level, + const std::string &arg = ""); + + logger::LogType getType() const {return static_cast(mType);} + logger::LogLevel getLevel() const {return static_cast(mLevel);} + std::string getArg() const {return mArg;} + + CONFIG_REGISTER + ( + mType, + mLevel, + mArg + ) +}; + + +} //namespace lxcpp + + +#endif // LXCPP_LOGGER_CONFIG_HPP diff --git a/libs/lxcpp/utils.cpp b/libs/lxcpp/utils.cpp new file mode 100644 index 0000000..41e76b5 --- /dev/null +++ b/libs/lxcpp/utils.cpp @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Lukasz Pawelczyk (l.pawelczyk@samsung.com) + * @brief LXCPP utils implementation + */ + +#include "lxcpp/exception.hpp" + +#include "logger/logger.hpp" +#include "utils/fd-utils.hpp" +#include "utils/exception.hpp" + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include + + +namespace lxcpp { + + +/* + * This function has to be safe in regard to signal(7) + */ +int nullStdFDs() +{ + int ret = -1; + + int fd = TEMP_FAILURE_RETRY(open("/dev/null", O_RDWR | O_CLOEXEC)); + if (fd == -1) { + goto err; + } + + if (-1 == TEMP_FAILURE_RETRY(::dup2(fd, STDIN_FILENO))) { + goto err_close; + } + + if (-1 == TEMP_FAILURE_RETRY(::dup2(fd, STDOUT_FILENO))) { + goto err_close; + } + + if (-1 == TEMP_FAILURE_RETRY(::dup2(fd, STDERR_FILENO))) { + goto err_close; + } + + if (-1 == TEMP_FAILURE_RETRY(::close(fd))) { + goto err_close; + } + + return 0; + +err_close: + TEMP_FAILURE_RETRY(::close(fd)); +err: + return ret; +} + +void setProcTitle(const std::string &title) +{ + std::ifstream f("/proc/self/stat"); + auto it = std::istream_iterator(f); + + // Skip the first 47 fields, entries 48-49 are ARG_START and ARG_END. + std::advance(it, 47); + unsigned long argStart = std::stol(*it++); + unsigned long argEnd = std::stol(*it++); + + f.close(); + + char *mem = reinterpret_cast(argStart); + ptrdiff_t oldLen = argEnd - argStart; + + // Include the null byte here, because in the calculations below we want to have room for it. + size_t newLen = title.length() + 1; + + // We shouldn't use more then we have available. Hopefully that should be enough. + if ((long)newLen > oldLen) { + newLen = oldLen; + } else { + argEnd = argStart + newLen; + } + + // Sanity check + if (argEnd < newLen || argEnd < argStart) { + std::string msg = "setProcTitle() failed: " + utils::getSystemErrorMessage(); + LOGE(msg); + throw UtilityException(msg); + } + + // Let's try to set the memory range properly (this requires capabilities) + if (::prctl(PR_SET_MM, PR_SET_MM_ARG_END, argEnd, 0, 0) < 0) { + // If that failed let's fall back to the poor man's version, just zero the memory we already have. + ::bzero(mem, oldLen); + } + + ::strcpy(mem, title.c_str()); +} + + +} // namespace lxcpp diff --git a/libs/lxcpp/utils.hpp b/libs/lxcpp/utils.hpp new file mode 100644 index 0000000..2a59303 --- /dev/null +++ b/libs/lxcpp/utils.hpp @@ -0,0 +1,54 @@ +/* + * Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1 as published by the Free Software Foundation. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file + * @author Lukasz Pawelczyk (l.pawelczyk@samsung.com) + * @brief LXCPP utils headers + */ + +#ifndef LXCPP_UTILS_HPP +#define LXCPP_UTILS_HPP + +#include + + +namespace lxcpp { + +/** + * Nullifies all standard file descriptors (stdin, stdout, stderr) + * replacing them with file descriptor to /dev/null. Used to + * as a part of a process to detach a process from a control terminal. + * + * This function has to be safe in regard to signal(7) + * + * @returns an error code in case of failure. + */ +int nullStdFDs(); + +/** + * Changes the tittle of a current process title (e.g. visible in ps tool). + * + * @param title A new tittle to be set + */ +void setProcTitle(const std::string &title); + + +} // namespace lxcpp + + +#endif // LXCPP_START_HPP diff --git a/packaging/vasum.spec b/packaging/vasum.spec index 2cd5dd8..7709ab4 100644 --- a/packaging/vasum.spec +++ b/packaging/vasum.spec @@ -487,6 +487,7 @@ The package provides liblxcpp library. %files -n liblxcpp %defattr(644,root,root,755) %{_libdir}/liblxcpp.so.0 +%attr(755,root,root) %{_libexecdir}/lxcpp-guard %attr(755,root,root) %{_libdir}/liblxcpp.so.%{version} %package -n liblxcpp-devel -- 2.7.4