From 273e398513a0cddef7039acc046c265ace94b282 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Wed, 14 Oct 2015 13:43:41 +0200 Subject: [PATCH 01/16] Don't force compiler colors by default, add an option for that [Feature] Make it possible to compile without colors. [Cause] Compilation can be on a terminal (or non-terminal) that does not understand them. [Solution] Add a cmake option to force compiler colors, by default they are "auto" [Verification] cmake -DVASUM_BUILD_FORCE_COMPILER_COLORS=true/false Change-Id: I60376daa9801e01901af2f9f8d9d3dd5d6c18494 --- CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0bd22e5..c0c800c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,9 @@ INCLUDE(GNUInstallDirs) IF (( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU" AND NOT (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9)) OR ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" )) - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always") + IF (VASUM_BUILD_FORCE_COMPILER_COLORS) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fdiagnostics-color=always") + ENDIF() ENDIF() ## Compiler flags, depending on the build type ################################# -- 2.7.4 From 31d69907cbefe58b1e923d95a26268683b6dec18 Mon Sep 17 00:00:00 2001 From: Krzysztof Dynowski Date: Thu, 3 Sep 2015 09:34:37 +0200 Subject: [PATCH 02/16] lxcpp: network implementation (part 3) [Feature] Network implementation for lxcpp (routing table manipulation) [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I983a4b565c4b9e1b07ae8ab568445729c0f80eb8 --- common/utils/execute.cpp | 1 + libs/lxcpp/container-impl.cpp | 2 +- libs/lxcpp/network.cpp | 376 +++++++++++++++++++++++++++++----- libs/lxcpp/network.hpp | 69 +++++-- tests/unit_tests/lxcpp/ut-network.cpp | 280 +++++++++++++++++++++---- 5 files changed, 625 insertions(+), 103 deletions(-) diff --git a/common/utils/execute.cpp b/common/utils/execute.cpp index d047a2e..29c888e 100644 --- a/common/utils/execute.cpp +++ b/common/utils/execute.cpp @@ -99,6 +99,7 @@ bool executeAndWait(const char* fname, const char* const* argv, int& status) bool success = executeAndWait([=]() { execv(fname, const_cast(argv)); + LOGE("execv failed: " << getSystemErrorMessage()); _exit(EXIT_FAILURE); }, status); if (!success) { diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp index 84f9b44..e19012c 100644 --- a/libs/lxcpp/container-impl.cpp +++ b/libs/lxcpp/container-impl.cpp @@ -240,7 +240,7 @@ NetworkInterfaceInfo ContainerImpl::getInterfaceInfo(const std::string& ifname) std::vector addrs; std::string macaddr; int mtu = 0, flags = 0; - Attrs attrs = ni.getAttrs(); + const Attrs& attrs = ni.getAttrs(); for (const Attr& a : attrs) { switch (a.name) { case AttrName::MAC: diff --git a/libs/lxcpp/network.cpp b/libs/lxcpp/network.cpp index 1214e5c..7b9c0b3 100644 --- a/libs/lxcpp/network.cpp +++ b/libs/lxcpp/network.cpp @@ -70,7 +70,18 @@ uint32_t getInterfaceIndex(const std::string& name) return index; } -uint32_t getInterfaceIndex(const std::string& name, pid_t pid) +std::string getInterfaceName(uint32_t index) +{ + char buf[IFNAMSIZ]; + if (::if_indextoname(index, buf) == NULL) { + const std::string msg = "No interface for index: " + std::to_string(index); + LOGE(msg); + throw NetworkException(msg); + } + return buf; +} + +uint32_t getInterfaceIndex(pid_t pid, const std::string& name) { NetlinkMessage nlm(RTM_GETLINK, NLM_F_REQUEST | NLM_F_ACK); ifinfomsg info = utils::make_clean(); @@ -81,7 +92,7 @@ uint32_t getInterfaceIndex(const std::string& name, pid_t pid) NetlinkResponse response = send(nlm, pid); if (!response.hasMessage()) { - const std::string msg = "Can't get interface index"; + const std::string msg = "Can't get interface index for " + name; LOGE(msg); throw NetworkException(msg); } @@ -90,7 +101,7 @@ uint32_t getInterfaceIndex(const std::string& name, pid_t pid) return info.ifi_index; } -void bridgeModify(const std::string& ifname, uint32_t masterIndex) { +void bridgeModify(pid_t pid, const std::string& ifname, uint32_t masterIndex) { NetlinkMessage nlm(RTM_SETLINK, NLM_F_REQUEST | NLM_F_ACK); ifinfomsg info = utils::make_clean(); info.ifi_family = AF_UNSPEC; @@ -98,12 +109,12 @@ void bridgeModify(const std::string& ifname, uint32_t masterIndex) { info.ifi_index = getInterfaceIndex(ifname); nlm.put(info) .put(IFLA_MASTER, masterIndex); - send(nlm); + send(nlm, pid); } -void getAddressList(std::vector& addrs, int family, const std::string& ifname, pid_t pid) +void getAddressList(pid_t pid, std::vector& addrs, int family, const std::string& ifname) { - uint32_t index = getInterfaceIndex(ifname, pid); + uint32_t index = getInterfaceIndex(pid, ifname); NetlinkMessage nlm(RTM_GETADDR, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP); ifaddrmsg infoAddr = utils::make_clean(); infoAddr.ifa_family = family; //test AF_PACKET to get all AF_INET* ? @@ -174,6 +185,33 @@ void getAddressList(std::vector& addrs, int family, const std::string& response.fetchNextMessage(); } } + +/* + * convert string-hex to byte array + */ +void toMacAddressArray(const std::string& s, char *buf, size_t bs) +{ + static const std::string hex = "0123456789ABCDEF"; + int nibble = 0; //nibble counter, one nibble = 4 bits (or one hex digit) + int v = 0; + ::memset(buf, 0, bs); + for (size_t i = 0; i < s.length() && bs > 0; ++i) { + const char c = s.at(i); + size_t pos = hex.find(c); + if (pos == std::string::npos) { // ignore eny non-hex character + continue; + } + v <<= 4; + v |= pos; // add nibble + if (++nibble == 2) { // two nibbles collected (one byte) + *buf++ = v; // assign the byte + --bs; // decrease space left + v = 0; // reset byte and nibble counter + nibble = 0; + } + } +} + } // anonymous namespace @@ -236,7 +274,9 @@ std::string toString(const InetAddr& a) { return ""; } -InetAddr::InetAddr(uint32_t f, int p, const std::string& a) +InetAddr::InetAddr(const std::string& a, unsigned p, uint32_t f) : + prefix(p), + flags(f) { if (a.find(":") != std::string::npos) { setType(InetAddrType::IPV6); @@ -245,8 +285,6 @@ InetAddr::InetAddr(uint32_t f, int p, const std::string& a) setType(InetAddrType::IPV4); fromString(a, getAddr()); } - flags = f; - prefix = p; } void NetworkInterface::create(InterfaceType type, @@ -285,7 +323,7 @@ void NetworkInterface::createVeth(const std::string& peerif) .endNested() .endNested() .endNested(); - send(nlm); + send(nlm, mContainerPid); } void NetworkInterface::createBridge() @@ -304,7 +342,7 @@ void NetworkInterface::createBridge() .endNested() .endNested() .put(IFLA_IFNAME, mIfname); //bridge name (will be created) - send(nlm); + send(nlm, mContainerPid); } void NetworkInterface::createMacVLan(const std::string& maserif, MacVLanMode mode) @@ -323,7 +361,7 @@ void NetworkInterface::createMacVLan(const std::string& maserif, MacVLanMode mod .endNested() .put(IFLA_LINK, index) //master index .put(IFLA_IFNAME, mIfname); //slave name (will be created) - send(nlm); + send(nlm, mContainerPid); } void NetworkInterface::moveToContainer(pid_t pid) @@ -334,7 +372,7 @@ void NetworkInterface::moveToContainer(pid_t pid) info.ifi_index = getInterfaceIndex(mIfname); nlm.put(info) .put(IFLA_NET_NS_PID, pid); - send(nlm); + send(nlm, mContainerPid); mContainerPid = pid; } @@ -345,28 +383,25 @@ void NetworkInterface::destroy() ifinfomsg info = utils::make_clean(); info.ifi_family = AF_UNSPEC; info.ifi_change = CHANGE_FLAGS_DEFAULT; - info.ifi_index = getInterfaceIndex(mIfname, mContainerPid); + info.ifi_index = getInterfaceIndex(mContainerPid, mIfname); nlm.put(info) .put(IFLA_IFNAME, mIfname); - send(nlm); + send(nlm, mContainerPid); } NetStatus NetworkInterface::status() const { - NetlinkMessage nlm(RTM_GETLINK, NLM_F_REQUEST | NLM_F_ACK); - ifinfomsg info = utils::make_clean(); - info.ifi_family = AF_UNSPEC; - info.ifi_change = CHANGE_FLAGS_DEFAULT; - nlm.put(info) - .put(IFLA_IFNAME, mIfname); - - NetlinkResponse response = send(nlm, mContainerPid); - if (!response.hasMessage()) { - throw NetworkException("Can't get interface information"); - } - - response.fetch(info); - return (info.ifi_flags & IFF_UP) != 0 ? NetStatus::UP : NetStatus::DOWN; + const Attrs& attrs = getAttrs(); + NetStatus st = NetStatus::DOWN; + for (const Attr& a : attrs) + if (a.name == AttrName::FLAGS) { + uint32_t f = stoul(a.value); + if (f & IFF_UP) { + st = NetStatus::UP; + break; + } + } + return st; } void NetworkInterface::renameFrom(const std::string& oldif) @@ -374,7 +409,7 @@ void NetworkInterface::renameFrom(const std::string& oldif) NetlinkMessage nlm(RTM_SETLINK, NLM_F_REQUEST | NLM_F_ACK); ifinfomsg info = utils::make_clean(); info.ifi_family = AF_UNSPEC; - info.ifi_index = getInterfaceIndex(oldif, mContainerPid); + info.ifi_index = getInterfaceIndex(mContainerPid, oldif); info.ifi_change = CHANGE_FLAGS_DEFAULT; nlm.put(info) @@ -384,15 +419,14 @@ void NetworkInterface::renameFrom(const std::string& oldif) void NetworkInterface::addToBridge(const std::string& bridge) { - bridgeModify(mIfname, getInterfaceIndex(bridge)); + bridgeModify(mContainerPid, mIfname, getInterfaceIndex(mContainerPid, bridge)); } void NetworkInterface::delFromBridge() { - bridgeModify(mIfname, 0); + bridgeModify(mContainerPid, mIfname, 0); } - void NetworkInterface::setAttrs(const Attrs& attrs) { if (attrs.empty()) { @@ -402,7 +436,7 @@ void NetworkInterface::setAttrs(const Attrs& attrs) //TODO check this: NetlinkMessage nlm(RTM_SETLINK, NLM_F_REQUEST | NLM_F_ACK); NetlinkMessage nlm(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK); ifinfomsg info = utils::make_clean(); - info.ifi_index = getInterfaceIndex(mIfname, mContainerPid); + info.ifi_index = getInterfaceIndex(mContainerPid, mIfname); info.ifi_family = AF_UNSPEC; info.ifi_change = CHANGE_FLAGS_DEFAULT; @@ -437,7 +471,9 @@ void NetworkInterface::setAttrs(const Attrs& attrs) nlm.put(IFLA_TXQLEN, txq); } if (!mac.empty()) { - nlm.put(IFLA_ADDRESS, mac); + char buf[6]; + toMacAddressArray(mac, buf, 6); + nlm.put(IFLA_ADDRESS, buf); } NetlinkResponse response = send(nlm, mContainerPid); @@ -460,8 +496,8 @@ Attrs NetworkInterface::getAttrs() const throw NetworkException("Can't get interface information"); } - Attrs attrs; response.fetch(info); + Attrs attrs; attrs.push_back(Attr{AttrName::FLAGS, std::to_string(info.ifi_flags)}); attrs.push_back(Attr{AttrName::TYPE, std::to_string(info.ifi_type)}); @@ -471,7 +507,7 @@ Attrs NetworkInterface::getAttrs() const * a few types of networks require 64-bit addresses instead. */ std::string mac; - uint32_t mtu, link, txq; + uint32_t tmp; int attrType = response.getAttributeType(); switch (attrType) { case IFLA_ADDRESS: //1 @@ -479,17 +515,18 @@ Attrs NetworkInterface::getAttrs() const attrs.push_back(Attr{AttrName::MAC, utils::toHexString(mac.c_str(), mac.size())}); break; case IFLA_MTU: //4 - response.fetch(IFLA_MTU, mtu); - attrs.push_back(Attr{AttrName::MTU, std::to_string(mtu)}); + response.fetch(IFLA_MTU, tmp); + attrs.push_back(Attr{AttrName::MTU, std::to_string(tmp)}); break; case IFLA_LINK://5 - response.fetch(IFLA_LINK, link); - attrs.push_back(Attr{AttrName::LINK, std::to_string(link)}); + response.fetch(IFLA_LINK, tmp); + attrs.push_back(Attr{AttrName::LINK, std::to_string(tmp)}); break; case IFLA_TXQLEN://13 - response.fetch(IFLA_TXQLEN, txq); - attrs.push_back(Attr{AttrName::TXQLEN, std::to_string(txq)}); + response.fetch(IFLA_TXQLEN, tmp); + attrs.push_back(Attr{AttrName::TXQLEN, std::to_string(tmp)}); break; + case IFLA_OPERSTATE://16 (IF_OPER_DOWN,...,IF_OPER_UP) case IFLA_BROADCAST://2 MAC broadcast case IFLA_IFNAME: //3 case IFLA_QDISC: //6 queue discipline @@ -500,6 +537,7 @@ Attrs NetworkInterface::getAttrs() const case IFLA_WIRELESS: //11 case IFLA_PROTINFO: //12 case IFLA_MAP: //14 + case IFLA_WEIGHT: //15 default: response.skipAttribute(); break; @@ -512,7 +550,7 @@ void NetworkInterface::addInetAddr(const InetAddr& addr) { NetlinkMessage nlm(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REQUEST | NLM_F_ACK); ifaddrmsg infoAddr = utils::make_clean(); - infoAddr.ifa_index = getInterfaceIndex(mIfname, mContainerPid); + infoAddr.ifa_index = getInterfaceIndex(mContainerPid, mIfname); infoAddr.ifa_family = addr.getType() == InetAddrType::IPV4 ? AF_INET : AF_INET6; infoAddr.ifa_prefixlen = addr.prefix; infoAddr.ifa_flags = addr.flags; @@ -533,7 +571,7 @@ void NetworkInterface::delInetAddr(const InetAddr& addr) { NetlinkMessage nlm(RTM_DELADDR, NLM_F_REQUEST | NLM_F_ACK); ifaddrmsg infoAddr = utils::make_clean(); - infoAddr.ifa_index = getInterfaceIndex(mIfname, mContainerPid); + infoAddr.ifa_index = getInterfaceIndex(mContainerPid, mIfname); infoAddr.ifa_family = addr.getType() == InetAddrType::IPV4 ? AF_INET : AF_INET6; infoAddr.ifa_prefixlen = addr.prefix; infoAddr.ifa_flags = addr.flags; @@ -553,10 +591,250 @@ void NetworkInterface::delInetAddr(const InetAddr& addr) std::vector NetworkInterface::getInetAddressList() const { std::vector addrs; - getAddressList(addrs, AF_UNSPEC, mIfname, mContainerPid); + getAddressList(mContainerPid, addrs, AF_UNSPEC, mIfname); return addrs; } +static rt_class_t getRoutingTableClass(const RoutingTable rt) +{ + switch (rt) { + case RoutingTable::UNSPEC: + return RT_TABLE_UNSPEC; //0 + case RoutingTable::COMPAT: + return RT_TABLE_COMPAT; //252 + case RoutingTable::DEFAULT: + return RT_TABLE_DEFAULT;//253 + case RoutingTable::MAIN: + return RT_TABLE_MAIN; //254 + case RoutingTable::LOCAL: + return RT_TABLE_LOCAL; //255 + default: //all other are user tables (1...251), but I use only '1' + return static_cast(1); + } +} +static RoutingTable getRoutingTable(unsigned tbl) +{ + switch (tbl) { + case RT_TABLE_UNSPEC: + return RoutingTable::UNSPEC; + case RT_TABLE_COMPAT: + return RoutingTable::COMPAT; + case RT_TABLE_DEFAULT: + return RoutingTable::DEFAULT; + case RT_TABLE_MAIN: + return RoutingTable::MAIN; + case RT_TABLE_LOCAL: + return RoutingTable::LOCAL; + default: + return RoutingTable::USER; + } +} + +void NetworkInterface::addRoute(const Route& route, const RoutingTable rt) +{ + InetAddrType type = route.dst.getType(); + if (route.src.getType() != type) { + const std::string msg = "Family type must be the same"; + LOGE(msg); + throw NetworkException(msg); + } + uint32_t index = getInterfaceIndex(mContainerPid, mIfname); + NetlinkMessage nlm(RTM_NEWROUTE, NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL | NLM_F_ACK); + + rtmsg msg = utils::make_clean(); + + if (type == InetAddrType::IPV6) { + msg.rtm_family = AF_INET6; + } else if (type == InetAddrType::IPV4) { + msg.rtm_family = AF_INET; + } + msg.rtm_table = getRoutingTableClass(rt); + msg.rtm_protocol = RTPROT_BOOT; + msg.rtm_scope = RT_SCOPE_UNIVERSE; + msg.rtm_type = RTN_UNICAST; + msg.rtm_dst_len = route.dst.prefix; + + nlm.put(msg); + + if (type == InetAddrType::IPV6) { + if (route.dst.prefix == 0) + nlm.put(RTA_GATEWAY, route.dst.getAddr()); + else + nlm.put(RTA_DST, route.dst.getAddr()); + + if (route.src.prefix == 128) { + nlm.put(RTA_PREFSRC, route.src.getAddr()); + } + } else if (type == InetAddrType::IPV4) { + if (route.dst.prefix == 0) + nlm.put(RTA_GATEWAY, route.dst.getAddr()); + else + nlm.put(RTA_DST, route.dst.getAddr()); + + if (route.src.prefix == 32) { + nlm.put(RTA_PREFSRC, route.src.getAddr()); + } + } + + nlm.put(RTA_OIF, index); + + send(nlm, mContainerPid); +} + +void NetworkInterface::delRoute(const Route& route, const RoutingTable rt) +{ + InetAddrType type = route.dst.getType(); + if (route.src.getType() != type) { + const std::string msg = "Family type must be the same"; + LOGE(msg); + throw NetworkException(msg); + } + uint32_t index = getInterfaceIndex(mContainerPid, mIfname); + NetlinkMessage nlm(RTM_DELROUTE, NLM_F_REQUEST | NLM_F_ACK); + + rtmsg msg = utils::make_clean(); + msg.rtm_scope = RT_SCOPE_NOWHERE; + msg.rtm_table = getRoutingTableClass(rt); + msg.rtm_dst_len = route.dst.prefix; + if (type == InetAddrType::IPV6) { + msg.rtm_family = AF_INET6; + } else if (type == InetAddrType::IPV4) { + msg.rtm_family = AF_INET; + } + nlm.put(msg); + + if (type == InetAddrType::IPV6) { + nlm.put(RTA_DST, route.dst.getAddr()); + } else if (type == InetAddrType::IPV4) { + nlm.put(RTA_DST, route.dst.getAddr()); + } + nlm.put(RTA_OIF, index); + + send(nlm, mContainerPid); +} + +static std::vector getRoutesImpl(pid_t pid, rt_class_t tbl, const std::string& ifname, int family) +{ + uint32_t searchindex = 0; + NetlinkMessage nlm(RTM_GETROUTE, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP); + ifinfomsg info = utils::make_clean(); + info.ifi_family = family; + info.ifi_change = CHANGE_FLAGS_DEFAULT; + + nlm.put(info); + + NetlinkResponse response = send(nlm, pid); + + if (!ifname.empty()) { + searchindex = getInterfaceIndex(pid, ifname); + } + + std::vector routes; + for ( ; response.hasMessage(); response.fetchNextMessage()) { + if (response.getMessageType() != RTM_NEWROUTE) { + LOGW("Not route info in response"); + continue; + } + rtmsg rt; + response.fetch(rt); + if (tbl != RT_TABLE_UNSPEC && rt.rtm_table != tbl) { + continue; + } + if (rt.rtm_flags & RTM_F_CLONED) { + continue; + } + + Route route; + uint32_t index = 0; + route.dst.flags = 0; + route.src.flags = 0; + route.dst.prefix = 0; + route.src.prefix = 0; + route.table = getRoutingTable(rt.rtm_table); + + if (rt.rtm_family == AF_INET6) { + route.dst.setType(InetAddrType::IPV6); + route.src.setType(InetAddrType::IPV6); + } else if (rt.rtm_family == AF_INET) { + route.dst.setType(InetAddrType::IPV4); + route.src.setType(InetAddrType::IPV4); + } else { + const std::string msg = "Unsupported inet family"; + LOGE(msg); + throw NetworkException(msg); + } + + route.dst.prefix = rt.rtm_dst_len; + while (response.hasAttribute()) { + std::string tmpval; + uint32_t tmp; + int attrType = response.getAttributeType(); + //int len = response.getAttributeLength(); + switch (attrType) { + case RTA_DST: // 1 + case RTA_GATEWAY:// 5 + if (route.dst.getType() == InetAddrType::IPV6) { + response.fetch(attrType, route.dst.getAddr()); + } else { + response.fetch(attrType, route.dst.getAddr()); + } + break; + case RTA_SRC: // 2 + case RTA_PREFSRC:// 7 + if (route.src.getType() == InetAddrType::IPV6) { + response.fetch(attrType, route.src.getAddr()); + route.src.prefix = 128; + } else { + response.fetch(attrType, route.src.getAddr()); + route.src.prefix = 32; + } + break; + case RTA_OIF: //4 + response.fetch(RTA_OIF, tmp); + index = tmp; + break; + case RTA_PRIORITY: // 6 + response.fetch(RTA_PRIORITY, tmp); + route.metric = tmp; + break; + case RTA_TABLE: //15 extends and ovewrites rt.rtm_table + response.fetch(RTA_TABLE, tmp); + route.table = getRoutingTable(tmp); + break; + + case RTA_CACHEINFO://12 + response.skipAttribute(); + break; + case RTA_IIF: // 3 + case RTA_METRICS: // 8 array of struct rtattr + case RTA_MULTIPATH:// 9 array of struct rtnexthop + case RTA_FLOW: //11 + default: + if (!searchindex) { + response.fetch(attrType, tmpval); + LOGW("rtAttr " << attrType << ":" << + utils::toHexString(tmpval.c_str(), tmpval.size())); + } else { + response.skipAttribute(); + } + break; + } + } + if (index == 0) continue; + + if (searchindex == 0 || searchindex == index) { + route.ifname = getInterfaceName(index); + routes.push_back(route); + } + } + return routes; +} + +std::vector NetworkInterface::getRoutes(const RoutingTable rt) const +{ + return getRoutesImpl(mContainerPid, getRoutingTableClass(rt), mIfname, AF_UNSPEC); +} + void NetworkInterface::up() { Attrs attrs; @@ -617,4 +895,10 @@ std::vector NetworkInterface::getInterfaces(pid_t initpid) return iflist; } +std::vector NetworkInterface::getRoutes(pid_t initpid, const RoutingTable rt) +{ + rt_class_t tbl = getRoutingTableClass(rt); + return getRoutesImpl(initpid, tbl, "", AF_UNSPEC); +} + } // namespace lxcpp diff --git a/libs/lxcpp/network.hpp b/libs/lxcpp/network.hpp index 0affc5f..ac94c44 100644 --- a/libs/lxcpp/network.hpp +++ b/libs/lxcpp/network.hpp @@ -54,8 +54,8 @@ enum class InetAddrType { */ class InetAddr { public: - InetAddr() {} - InetAddr(uint32_t flags, int prefix, const std::string& addr); + InetAddr() = default; + InetAddr(const std::string& addr, unsigned prefix, uint32_t flags=0); InetAddrType getType() const { return static_cast(type); @@ -77,8 +77,8 @@ public: return *(reinterpret_cast(v)); } + unsigned prefix; uint32_t flags; - int prefix; CONFIG_REGISTER ( @@ -127,7 +127,9 @@ enum class RoutingTable { LOCAL, USER, }; -inline std::string toString(RoutingTable rt) { + +inline std::string toString(const RoutingTable rt) +{ switch (rt) { case RoutingTable::UNSPEC: return "unspec"; @@ -144,6 +146,14 @@ inline std::string toString(RoutingTable rt) { } } +struct Route { + InetAddr dst; + InetAddr src; + unsigned metric; + std::string ifname; + RoutingTable table; +}; + enum class AttrName { MAC, FLAGS, @@ -205,10 +215,10 @@ std::string toString(const InetAddr& a); * operates on netlink device */ class NetworkInterface { + //TODO implement Netlink singleton per pid public: /** * Create network interface object for the ifname in the container (network namespace) - * Note: pid=0 is kernel */ NetworkInterface(const std::string& ifname, pid_t pid = 0) : mIfname(ifname), @@ -224,7 +234,8 @@ public: NetStatus status() const; /** - * Create network interface in container identified by mContainerPid + * Create network interface in container identified by @mContainerPid + * * Equivalent to: ip link add @mIfname type @type [...] * Create pair of virtual ethernet interfaces * ip link add @mIfname type veth peer name @peerif @@ -233,7 +244,7 @@ public: * Create psedo-ethernet interface on existing one * ip link add @mIfname type macvlan link @peerif [mode @a mode] */ - void create(InterfaceType type, const std::string& peerif, MacVLanMode mode = MacVLanMode::PRIVATE); + void create(InterfaceType type, const std::string& peerif = "", MacVLanMode mode = MacVLanMode::PRIVATE); /** * Delete interface @@ -243,9 +254,9 @@ public: /** * Move interface to container - * Equivalent to: ip link set dev @hostif netns @mContainerPid + * Equivalent to: ip link set dev @mIfname netns @pid */ - void moveToContainer(pid_t p); + void moveToContainer(pid_t pid); /** * Rename interface name @@ -291,8 +302,26 @@ public: std::vector getInetAddressList() const; /** + * Add route to specified routing table + * Equivalent to: ip route add @route.dst.addr/@route.dst.prefix dev @mIfname (if route.src.prefix=0) + */ + void addRoute(const Route& route, const RoutingTable rt = RoutingTable::MAIN); + + /** + * Remove route from specified routing table + * Equivalent to: ip route del @route.dst.addr dev @mIfname + */ + void delRoute(const Route& route, const RoutingTable rt = RoutingTable::MAIN); + + /** + * Retrieve routing table for the interface + * Equivalent to: ip route show dev @mIfname table @rt + */ + std::vector getRoutes(const RoutingTable rt = RoutingTable::MAIN) const; + + /** * Set interface up - * Equivalent to: ip link set @mInface up + * Equivalent to: ip link set @mIfname up */ void up(); @@ -304,20 +333,26 @@ public: /** * Set MAC address attribute - * Equivalent to: ip link set @mIface address @macaddr + * Equivalent to: ip link set @mIfname address @macaddr * @macaddr in format AA:BB:CC:DD:FF:GG + * + * Note: two lower bits of first byte (leftmost) specifies MAC address class: + * b1: 0=unicast, 1=broadcast + * b2: 0=global, 1=local + * in most cases should be b2=0, b1=1 + * (see: https://en.wikipedia.org/wiki/MAC_address) */ void setMACAddress(const std::string& macaddr); /** * Set MTU attribute - * Equivalent to: ip link set @mIface mtu @mtu + * Equivalent to: ip link set @mIfname mtu @mtu */ void setMTU(int mtu); /** * Set TxQ attribute - * Equivalent to: ip link set @mIface txqueue @txlen + * Equivalent to: ip link set @mIfname txqueue @txlen */ void setTxLength(int txlen); @@ -327,11 +362,19 @@ public: */ static std::vector getInterfaces(pid_t initpid); + /** + * Get list of routes (specified routing table) + * Equivalent to: ip route show table @rt + */ + static std::vector getRoutes(pid_t initpid, const RoutingTable rt = RoutingTable::MAIN); + private: void createVeth(const std::string& peerif); void createBridge(); void createMacVLan(const std::string& masterif, MacVLanMode mode); + void modifyRoute(int cmd, const InetAddr& src, const InetAddr& dst); + const std::string mIfname; ///< network interface name inside zone pid_t mContainerPid; ///< Container pid to operate on (0 means kernel) }; diff --git a/tests/unit_tests/lxcpp/ut-network.cpp b/tests/unit_tests/lxcpp/ut-network.cpp index f797a6c..a4741f6 100644 --- a/tests/unit_tests/lxcpp/ut-network.cpp +++ b/tests/unit_tests/lxcpp/ut-network.cpp @@ -23,7 +23,10 @@ #include "config.hpp" #include "config/manager.hpp" +#include "logger/logger.hpp" #include "lxcpp/network-config.hpp" +#include "lxcpp/process.hpp" +#include "utils/execute.hpp" #include "ut.hpp" #include @@ -31,10 +34,9 @@ #include -namespace { - using namespace lxcpp; -using namespace config; + +namespace { struct Fixture { Fixture() {} @@ -49,8 +51,71 @@ struct Fixture { } while (std::find(iflist.begin(), iflist.end(), name) != iflist.end()); return name; } + + static void sendCmd(int fd, const char *txt) { + if (::write(fd, txt, 2) != 2) { + throw std::runtime_error("pipe write error"); + } + } }; + +int child_exec(void *_fd) +{ + int *fd = (int *)_fd; + char cmdbuf[2]; + char cmd = '-'; + + ::close(fd[1]); + try { + lxcpp::NetworkInterface("lo").up(); + for(;;) { + // child: waiting for parent + if (::read(fd[0], cmdbuf, 2) != 2) { + break; + } + + cmd = cmdbuf[0]; + + if (cmd == '0') { + break; + } else if (cmd == 'a') { + const char *argv[] = { + "ip", "a", NULL + }; + if (!utils::executeAndWait("/sbin/ip", argv)) { + throw std::runtime_error("ip addr failed"); + } + } else if (cmd == 'r') { + const char *argv[] = { + "ip", "route", "list", NULL + }; + if (!utils::executeAndWait("/sbin/ip", argv)) { + throw std::runtime_error("ip route failed"); + } + } else if (cmd == 's') { + const char *argv[] = { + "bash", NULL + }; + if (!utils::executeAndWait("/bin/bash", argv)) { + throw std::runtime_error("bash failed"); + } + } else if (cmd == 'c') { + LOGW("connecting ... to be done"); + } else { + continue; + } + } + + //cleanup + ::close(fd[0]); + _exit(EXIT_SUCCESS); + + } catch(...) { + _exit(EXIT_FAILURE); + } +} + } // namespace /* @@ -64,31 +129,12 @@ BOOST_FIXTURE_TEST_SUITE(LxcppNetworkSuite, Fixture) BOOST_AUTO_TEST_CASE(NetworkListInterfaces) { std::vector iflist; - BOOST_CHECK_NO_THROW(iflist = NetworkInterface::getInterfaces(0)); - - for (const auto& i : iflist) { - NetworkInterface ni(i); - std::cout << i << ": "; - Attrs attrs; - std::vector addrs; - BOOST_CHECK_NO_THROW(attrs = ni.getAttrs()); - for (const Attr& a : attrs) { - std::cout << a.name << "=" << a.value; - if (a.name == AttrName::FLAGS) { - uint32_t f = stoul(a.value); - std::cout << "("; - std::cout << ((f & IFF_UP) !=0 ? "UP" : "DONW"); - std::cout << ")"; - } - std::cout << "; "; - } - std::cout << std::endl; - - BOOST_CHECK_NO_THROW(addrs = ni.getInetAddressList()); - for (const InetAddr& a : addrs) { - std::cout << " " << toString(a) << std::endl; - } + BOOST_CHECK_NO_THROW(iflist=NetworkInterface::getInterfaces(0)); + for (const auto& ifn : iflist) { + const Attrs& attrs = NetworkInterface(ifn).getAttrs(); + BOOST_CHECK(attrs.size() > 0); } + } BOOST_AUTO_TEST_CASE(NetworkConfigSerialization) @@ -101,8 +147,7 @@ BOOST_AUTO_TEST_CASE(NetworkConfigSerialization) cfg.addInterfaceConfig("host-veth1", "zone-eth1", InterfaceType::BRIDGE); cfg.addInterfaceConfig("host-veth2", "zone-eth2", InterfaceType::MACVLAN); - InetAddr addr(0, 24, "1.2.3.4"); - cfg.addInetConfig("zone-eth0", addr); + cfg.addInetConfig("zone-eth0", InetAddr("1.2.3.4", 24)); config::saveToJsonFile(tmpConfigFile, cfg); @@ -120,30 +165,27 @@ BOOST_AUTO_TEST_CASE(NetworkConfigSerialization) BOOST_CHECK(ni1.getMode() == ni2.getMode()); } } + BOOST_AUTO_TEST_CASE(NetworkBridgeCreateDestroy) { - std::string name = getUniqueName("lolo"); + std::string name = getUniqueName("test-br"); NetworkInterface ni(name); - InetAddr myip(0, 32, "10.100.1.1"); + InetAddr myip("10.100.1.1", 32); - BOOST_CHECK_NO_THROW(ni.create(InterfaceType::BRIDGE, "")); - BOOST_CHECK_NO_THROW(ni.addInetAddr(myip);) + BOOST_CHECK_NO_THROW(ni.create(InterfaceType::BRIDGE)); + ni.setMACAddress("12:22:33:44:55:66"); // note bit0=0 within first byte !!! + BOOST_CHECK_NO_THROW(ni.addInetAddr(myip)); std::vector iflist = NetworkInterface::getInterfaces(0); BOOST_CHECK(std::find(iflist.begin(), iflist.end(), name) != iflist.end()); std::vector addrs = ni.getInetAddressList(); BOOST_CHECK(std::find(addrs.begin(), addrs.end(), myip) != addrs.end()); - for (const auto& i : iflist) { - std::cout << " " << i; - } - std::cout << std::endl; - for (const InetAddr& a : addrs) { - std::cout << " " << toString(a) << std::endl; - } BOOST_CHECK_NO_THROW(ni.delInetAddr(myip)); BOOST_CHECK_NO_THROW(ni.destroy()); + iflist = NetworkInterface::getInterfaces(0); + BOOST_CHECK(std::find(iflist.begin(), iflist.end(), ni.getName()) == iflist.end()); } BOOST_AUTO_TEST_CASE(NetworkMacVLanCreateDestroy) @@ -151,7 +193,9 @@ BOOST_AUTO_TEST_CASE(NetworkMacVLanCreateDestroy) std::string masterif; std::vector iflist = NetworkInterface::getInterfaces(0); for (const auto& ifn : iflist) { - if (ifn == "lo") continue; + if (ifn == "lo") { + continue; + } NetworkInterface n(ifn); if (n.status() == NetStatus::UP) { masterif = ifn; @@ -159,14 +203,164 @@ BOOST_AUTO_TEST_CASE(NetworkMacVLanCreateDestroy) } } - NetworkInterface ni(getUniqueName("lolo")); - std::cout << " creating MACVLAN on " << masterif << std::endl; + NetworkInterface ni(getUniqueName("test-vlan")); + // creating MACVLAN on masterif BOOST_CHECK_NO_THROW(ni.create(InterfaceType::MACVLAN, masterif, MacVLanMode::VEPA)); iflist = NetworkInterface::getInterfaces(0); BOOST_CHECK(std::find(iflist.begin(), iflist.end(), ni.getName()) != iflist.end()); + // destroy MACVLAN BOOST_CHECK_NO_THROW(ni.destroy()); + + iflist = NetworkInterface::getInterfaces(0); + BOOST_CHECK(std::find(iflist.begin(), iflist.end(), ni.getName()) == iflist.end()); +} + +BOOST_AUTO_TEST_CASE(NetworkListRoutes) +{ + unsigned mainLo = 0; + std::vector routes; + // tbl MAIN, all devs + BOOST_CHECK_NO_THROW(routes = NetworkInterface::getRoutes(0)); + for (auto route : routes) { + if (route.ifname == "lo") { + ++mainLo; + } + } + + // tbl LOCAL, all devs + BOOST_CHECK_NO_THROW(routes = NetworkInterface::getRoutes(0,RoutingTable::LOCAL)); + + // tbl DEFAULT, all devs + BOOST_CHECK_NO_THROW(routes = NetworkInterface::getRoutes(0,RoutingTable::DEFAULT)); + + NetworkInterface ni("lo"); + // tbl MAIN, dev lo + BOOST_CHECK_NO_THROW(routes = ni.getRoutes()); + BOOST_CHECK(routes.size() == mainLo); + + // tbl LOCAL, dev lo + BOOST_CHECK_NO_THROW(routes = ni.getRoutes(RoutingTable::LOCAL)); +} + +BOOST_AUTO_TEST_CASE(NetworkAddDelRoute) +{ + std::vector routes; + + Route route = { + InetAddr("10.100.1.0", 24),//dst - destination network + InetAddr("", 0), //src - not specified (prefix=0) + 0, // metric + "", // ifname (used only when read routes) + RoutingTable::UNSPEC // table (used only when read rotes) + }; + + NetworkInterface ni("lo"); + + BOOST_CHECK_NO_THROW(ni.addRoute(route)); + BOOST_CHECK_NO_THROW(routes = ni.getRoutes()); + BOOST_CHECK(std::find_if(routes.begin(), routes.end(), + [&route](const Route& item) -> bool { + return item.dst == route.dst; + } + ) != routes.end() + ); + + BOOST_CHECK_NO_THROW(ni.delRoute(route)); + BOOST_CHECK_NO_THROW(routes = ni.getRoutes()); + BOOST_CHECK(std::find_if(routes.begin(), routes.end(), + [&route](const Route& item) -> bool { + return item.dst == route.dst; + } + ) == routes.end() + ); +} + +BOOST_AUTO_TEST_CASE(NetworkNamespaceCreate) +{ + int fd[2]; + int r = ::pipe(fd); + BOOST_CHECK(r != -1); + + pid_t pid = lxcpp::clone(child_exec, fd, CLONE_NEWNET); + ::close(fd[0]); + + //directives for child process + sendCmd(fd[1], "0"); // exit + + // waiting for child to finish + int status; + BOOST_CHECK_NO_THROW(status = lxcpp::waitpid(pid)); + + ::close(fd[1]); + BOOST_CHECK_MESSAGE(status == 0, "child failed"); +} + +// this test case shows how to create container with network +// Note: this test needs some preparation to successfuly connect an external site: +// 1. allow network forwading (echo 1 > /proc/sys/net/ipv4/ip_forward) +// 2. configure ip masquarading (iptables -t nat -A POSTROUTING -s 10.0.0.0/16 ! -d 10.0.0.0/16 -j MASQUERADE) +BOOST_AUTO_TEST_CASE(NetworkNamespaceVETH) +{ + const char *vbr = "vbr"; + const char *veth1 = "veth-ma"; + const char *veth2 = "veth-sl"; + + int fd[2]; + int r = ::pipe(fd); + BOOST_CHECK(r != -1); + + pid_t pid = lxcpp::clone(child_exec, fd, CLONE_NEWNET); + ::close(fd[0]); + + NetworkInterface br(vbr); + NetworkInterface v1(veth1); + NetworkInterface v2(veth2); + + NetworkInterface("lo", pid).up(); + + // creating Bridge vbr + BOOST_CHECK_NO_THROW(br.create(InterfaceType::BRIDGE)); + BOOST_CHECK_NO_THROW(br.up()); + br.addInetAddr(InetAddr("10.0.0.1", 24)); + + // creating VETH pair veth1 <-> veth2 + BOOST_CHECK_NO_THROW(v1.create(InterfaceType::VETH, v2.getName())); + + // add veth1 to bridge + BOOST_CHECK_NO_THROW(v1.addToBridge(br.getName())); + + // move veth2 to network namespace (container) + BOOST_CHECK_NO_THROW(v2.moveToContainer(pid)); + v2.up(); + v2.addInetAddr(InetAddr("10.0.0.2", 24)); + + v1.up(); // after v2 up and configured + + // add default route + v2.addRoute(Route{ + InetAddr("10.0.0.1", 0), //dst - gateway + InetAddr("", 0), //src - not specified (prefix=0) + 0, + "", + RoutingTable::UNSPEC + }); + + //directives for child process + sendCmd(fd[1], "a"); // ip addr show + sendCmd(fd[1], "r"); // ip route list + sendCmd(fd[1], "c"); // connect extern (needs configured NAT) + //sendCmd(fd[1], "s"); // exec shell + sendCmd(fd[1], "0"); // exit + + // waiting for child to finish + int status; + BOOST_CHECK_NO_THROW(status = lxcpp::waitpid(pid)); + ::close(fd[1]); + BOOST_CHECK_MESSAGE(status == 0, "child failed"); + + BOOST_CHECK_NO_THROW(br.destroy()); } BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 70c609070756512c76ab883311dae531c27a8d37 Mon Sep 17 00:00:00 2001 From: "Maciej J. Karpiuk" Date: Thu, 15 Oct 2015 11:42:52 +0200 Subject: [PATCH 03/16] lxcpp: provisioning implementation (part 1) [Feature] Provisioning implementation for lxcpp (declare, list, remove) [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I3823587de023a9f1a9e34208ae9e188521dbe3b1 --- libs/lxcpp/commands/command.hpp | 6 +- libs/lxcpp/commands/provision.cpp | 89 +++++++++++++++ libs/lxcpp/commands/provision.hpp | 116 ++++++++++++++++++++ libs/lxcpp/container-config.hpp | 12 +- libs/lxcpp/container-impl.cpp | 98 ++++++++++++++++- libs/lxcpp/container-impl.hpp | 22 ++++ libs/lxcpp/container.hpp | 23 ++++ libs/lxcpp/exception.hpp | 5 + libs/lxcpp/guard/guard.cpp | 9 ++ libs/lxcpp/provision-config.cpp | 115 +++++++++++++++++++ libs/lxcpp/provision-config.hpp | 170 +++++++++++++++++++++++++++++ tests/unit_tests/lxcpp/ut-provisioning.cpp | 164 ++++++++++++++++++++++++++++ 12 files changed, 826 insertions(+), 3 deletions(-) create mode 100644 libs/lxcpp/commands/provision.cpp create mode 100644 libs/lxcpp/commands/provision.hpp create mode 100644 libs/lxcpp/provision-config.cpp create mode 100644 libs/lxcpp/provision-config.hpp create mode 100644 tests/unit_tests/lxcpp/ut-provisioning.cpp diff --git a/libs/lxcpp/commands/command.hpp b/libs/lxcpp/commands/command.hpp index cd301ee..a1ba473 100644 --- a/libs/lxcpp/commands/command.hpp +++ b/libs/lxcpp/commands/command.hpp @@ -28,9 +28,13 @@ namespace lxcpp { class Command { public: + // do sth [mandatory] virtual void execute() = 0; + + // roll-back execute() action [optional] + virtual void revert() {} }; } // namespace lxcpp -#endif // LXCPP_COMMANDS_COMMAND_HPP \ No newline at end of file +#endif // LXCPP_COMMANDS_COMMAND_HPP diff --git a/libs/lxcpp/commands/provision.cpp b/libs/lxcpp/commands/provision.cpp new file mode 100644 index 0000000..ba97393 --- /dev/null +++ b/libs/lxcpp/commands/provision.cpp @@ -0,0 +1,89 @@ +/* + * 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 Maciej Karpiuk (m.karpiuk2@samsung.com) + * @brief Add new provisioned file/dir/link/mount command + */ + +#include "lxcpp/commands/provision.hpp" +#include "lxcpp/container.hpp" +#include "lxcpp/provision-config.hpp" + +namespace lxcpp { + +void Provisions::execute() +{ + for(const auto & file : mConfig.mProvisions.files) { + ProvisionFile(mConfig, file).execute(); + } + + for(const auto & mount : mConfig.mProvisions.mounts) { + ProvisionMount(mConfig, mount).execute(); + } + + for(const auto & link : mConfig.mProvisions.links) { + ProvisionLink(mConfig, link).execute(); + } +} +void Provisions::revert() +{ + for(const auto & file : mConfig.mProvisions.files) { + ProvisionFile(mConfig, file).revert(); + } + + for(const auto & mount : mConfig.mProvisions.mounts) { + ProvisionMount(mConfig, mount).revert(); + } + + for(const auto & link : mConfig.mProvisions.links) { + ProvisionLink(mConfig, link).revert(); + } +} + + +void ProvisionFile::execute() +{ + // MJK TODO: add file +} +void ProvisionFile::revert() +{ + // MJK TODO: remove file from container +} + + +void ProvisionMount::execute() +{ + // MJK TODO: add mount +} +void ProvisionMount::revert() +{ + // MJK TODO: remove mount from container +} + + +void ProvisionLink::execute() +{ + // MJK TODO: add link +} +void ProvisionLink::revert() +{ + // MJK TODO: remove link from container +} + +} // namespace lxcpp diff --git a/libs/lxcpp/commands/provision.hpp b/libs/lxcpp/commands/provision.hpp new file mode 100644 index 0000000..0b7411a --- /dev/null +++ b/libs/lxcpp/commands/provision.hpp @@ -0,0 +1,116 @@ +/* + * 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 Maciej Karpiuk (m.karpiuk2@samsung.com) + * @brief Add new provisioned file/dir/link/mount command + */ + +#ifndef LXCPP_COMMAND_PROVISION_HPP +#define LXCPP_COMMAND_PROVISION_HPP + +#include "lxcpp/commands/command.hpp" +#include "lxcpp/container-config.hpp" +#include "lxcpp/provision-config.hpp" + +#include + +namespace lxcpp { + +class Provisions final: Command { +public: + /** + * Runs call in the container's context + * + * Add/remove all file/fifo/dir/mount/link provisions to/from the container + */ + Provisions(ContainerConfig &config) : mConfig(config) + { + } + + void execute(); + void revert(); + +private: + ContainerConfig& mConfig; +}; + + +class ProvisionFile final: Command { +public: + /** + * Runs call in the container's context + * + * Add/remove new file/fifo/dir provision to/from the container + */ + ProvisionFile(ContainerConfig &config, const provision::File &file) : + mConfig(config), mFile(file) + { + } + + void execute(); + void revert(); + +private: + ContainerConfig& mConfig; + const provision::File& mFile; +}; + +class ProvisionMount final: Command { +public: + /** + * Runs call in the container's context + * + * Add/remove new mount provision to/from the container + */ + ProvisionMount(ContainerConfig &config, const provision::Mount &mount) : + mConfig(config), mMount(mount) + { + } + + void execute(); + void revert(); + +private: + ContainerConfig& mConfig; + const provision::Mount& mMount; +}; + +class ProvisionLink final: Command { +public: + /** + * Runs call in the container's context + * + * Add/remove link provision to/from the container + */ + ProvisionLink(ContainerConfig &config, const provision::Link &link) : + mConfig(config), mLink(link) + { + } + + void execute(); + void revert(); + +private: + ContainerConfig& mConfig; + const provision::Link& mLink; +}; + +} // namespace lxcpp + +#endif // LXCPP_COMMAND_PROVISION_HPP diff --git a/libs/lxcpp/container-config.hpp b/libs/lxcpp/container-config.hpp index 4fbf86d..1a487cf 100644 --- a/libs/lxcpp/container-config.hpp +++ b/libs/lxcpp/container-config.hpp @@ -27,6 +27,7 @@ #include "lxcpp/logger-config.hpp" #include "lxcpp/network-config.hpp" #include "lxcpp/terminal-config.hpp" +#include "lxcpp/provision-config.hpp" #include #include @@ -117,6 +118,14 @@ struct ContainerConfig { */ int mNamespaces; + /** + * available files/dirs/mounts/links + * + * Set: by container provision manipulation methods + * Get: getFiles(), getMounts(), getLinks() + */ + ProvisionConfig mProvisions; + ContainerConfig() : mGuardPid(-1), mInitPid(-1), mNamespaces(0) {} CONFIG_REGISTER @@ -128,7 +137,8 @@ struct ContainerConfig { mInit, mLogger, mTerminals, - mNamespaces + mNamespaces, + mProvisions ) }; diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp index e19012c..29d6cb0 100644 --- a/libs/lxcpp/container-impl.cpp +++ b/libs/lxcpp/container-impl.cpp @@ -31,6 +31,7 @@ #include "lxcpp/commands/start.hpp" #include "lxcpp/commands/stop.hpp" #include "lxcpp/commands/prep-host-terminal.hpp" +#include "lxcpp/commands/provision.hpp" #include "logger/logger.hpp" #include "utils/exception.hpp" @@ -170,7 +171,7 @@ void ContainerImpl::start() void ContainerImpl::stop() { - // TODO: things to do when shuttting down the container: + // TODO: things to do when shutting down the container: // - close PTY master FDs from the config so we won't keep PTYs open Stop stop(mConfig); @@ -215,6 +216,12 @@ void ContainerImpl::console() console.execute(); } +bool ContainerImpl::isRunning() const +{ + // TODO: race condition may occur, sync needed + return getInitPid() != -1; +} + void ContainerImpl::addInterfaceConfig(const std::string& hostif, const std::string& zoneif, InterfaceType type, @@ -305,4 +312,93 @@ void ContainerImpl::delInetAddr(const std::string& ifname, const InetAddr& addr) ni.delInetAddr(addr); } +void ContainerImpl::declareFile(const provision::File::Type type, + const std::string& path, + const int32_t flags, + const int32_t mode) +{ + provision::File newFile({type, path, flags, mode}); + mConfig.mProvisions.addFile(newFile); + // TODO: update guard config + + if (isRunning()) { + ProvisionFile fileCmd(mConfig, newFile); + fileCmd.execute(); + } +} + +const FileVector& ContainerImpl::getFiles() const +{ + return mConfig.mProvisions.getFiles(); +} + +void ContainerImpl::removeFile(const provision::File& item) +{ + mConfig.mProvisions.removeFile(item); + + if (isRunning()) { + ProvisionFile fileCmd(mConfig, item); + fileCmd.revert(); + } +} + +void ContainerImpl::declareMount(const std::string& source, + const std::string& target, + const std::string& type, + const int64_t flags, + const std::string& data) +{ + provision::Mount newMount({source, target, type, flags, data}); + mConfig.mProvisions.addMount(newMount); + // TODO: update guard config + + if (isRunning()) { + ProvisionMount mountCmd(mConfig, newMount); + mountCmd.execute(); + } +} + +const MountVector& ContainerImpl::getMounts() const +{ + return mConfig.mProvisions.getMounts(); +} + +void ContainerImpl::removeMount(const provision::Mount& item) +{ + mConfig.mProvisions.removeMount(item); + + if (isRunning()) { + ProvisionMount mountCmd(mConfig, item); + mountCmd.revert(); + } +} + +void ContainerImpl::declareLink(const std::string& source, + const std::string& target) +{ + provision::Link newLink({source, target}); + mConfig.mProvisions.addLink(newLink); + // TODO: update guard config + + if (isRunning()) { + ProvisionLink linkCmd(mConfig, newLink); + linkCmd.execute(); + } +} + +const LinkVector& ContainerImpl::getLinks() const +{ + return mConfig.mProvisions.getLinks(); +} + +void ContainerImpl::removeLink(const provision::Link& item) +{ + mConfig.mProvisions.removeLink(item); + + if (isRunning()) { + ProvisionLink linkCmd(mConfig, item); + linkCmd.revert(); + } +} + } // namespace lxcpp diff --git a/libs/lxcpp/container-impl.hpp b/libs/lxcpp/container-impl.hpp index d3db492..f1cba58 100644 --- a/libs/lxcpp/container-impl.hpp +++ b/libs/lxcpp/container-impl.hpp @@ -69,6 +69,7 @@ public: void attach(const std::vector& argv, const std::string& cwdInContainer); void console(); + bool isRunning() const; // Network interfaces setup/config /** @@ -96,6 +97,27 @@ public: void addInetAddr(const std::string& ifname, const InetAddr& addr); void delInetAddr(const std::string& ifname, const InetAddr& addr); + // Provisioning + void declareFile(const provision::File::Type type, + const std::string& path, + const int32_t flags, + const int32_t mode); + const FileVector& getFiles() const; + void removeFile(const provision::File& item); + + void declareMount(const std::string& source, + const std::string& target, + const std::string& type, + const int64_t flags, + const std::string& data); + const MountVector& getMounts() const; + void removeMount(const provision::Mount& item); + + void declareLink(const std::string& source, + const std::string& target); + const LinkVector& getLinks() const; + void removeLink(const provision::Link& item); + private: ContainerConfig mConfig; }; diff --git a/libs/lxcpp/container.hpp b/libs/lxcpp/container.hpp index 096463b..2d0e696 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/provision-config.hpp" #include "lxcpp/logger-config.hpp" #include @@ -78,6 +79,7 @@ public: virtual void attach(const std::vector& argv, const std::string& cwdInContainer) = 0; virtual void console() = 0; + virtual bool isRunning() const = 0; // Network interfaces setup/config virtual void addInterfaceConfig(const std::string& hostif, @@ -100,6 +102,27 @@ public: virtual void setDown(const std::string& ifname) = 0; virtual void addInetAddr(const std::string& ifname, const InetAddr& addr) = 0; virtual void delInetAddr(const std::string& ifname, const InetAddr& addr) = 0; + + // Provisioning + virtual void declareFile(const provision::File::Type type, + const std::string& path, + const int32_t flags, + const int32_t mode) = 0; + virtual const FileVector& getFiles() const = 0; + virtual void removeFile(const provision::File& item) = 0; + + virtual void declareMount(const std::string& source, + const std::string& target, + const std::string& type, + const int64_t flags, + const std::string& data) = 0; + virtual const MountVector& getMounts() const = 0; + virtual void removeMount(const provision::Mount& item) = 0; + + virtual void declareLink(const std::string& source, + const std::string& target) = 0; + virtual const LinkVector& getLinks() const = 0; + virtual void removeLink(const provision::Link& item) = 0; }; } // namespace lxcpp diff --git a/libs/lxcpp/exception.hpp b/libs/lxcpp/exception.hpp index 387e2eb..37fec5a 100644 --- a/libs/lxcpp/exception.hpp +++ b/libs/lxcpp/exception.hpp @@ -96,6 +96,11 @@ struct ConfigureException: public Exception { : Exception(message) {} }; +struct ProvisionException: public Exception { + explicit ProvisionException(const std::string& message = "Provision error") + : Exception(message) {} +}; + } // namespace lxcpp #endif // LXCPP_EXCEPTION_HPP diff --git a/libs/lxcpp/guard/guard.cpp b/libs/lxcpp/guard/guard.cpp index 4f56771..f96fe7a 100644 --- a/libs/lxcpp/guard/guard.cpp +++ b/libs/lxcpp/guard/guard.cpp @@ -25,6 +25,7 @@ #include "lxcpp/guard/guard.hpp" #include "lxcpp/process.hpp" #include "lxcpp/commands/prep-guest-terminal.hpp" +#include "lxcpp/commands/provision.hpp" #include "config/manager.hpp" #include "logger/logger.hpp" @@ -42,6 +43,9 @@ int startContainer(void* data) // TODO: container preparation part 2 + Provisions provisions(config); + provisions.execute(); + PrepGuestTerminal terminals(config.mTerminals); terminals.execute(); @@ -96,6 +100,11 @@ int Guard::execute() int status = lxcpp::waitpid(initPid); LOGD("Init exited with status: " << status); + + // TODO: cleanup after child exits + Provisions provisions(mConfig); + provisions.revert(); + return status; } diff --git a/libs/lxcpp/provision-config.cpp b/libs/lxcpp/provision-config.cpp new file mode 100644 index 0000000..459ba70 --- /dev/null +++ b/libs/lxcpp/provision-config.cpp @@ -0,0 +1,115 @@ +/* + * 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 Maciej Karpiuk (m.karpiuk2@samsung.com) + * @brief Provisioning configuration + */ + +#include +#include +#include "lxcpp/container-config.hpp" + +using namespace lxcpp; +using namespace provision; + +void ProvisionConfig::addFile(const File& newFile) +{ + auto it = std::find(files.begin(), files.end(), newFile); + if (it != files.end()) { + const std::string msg = + "Can't add file. Provision already exists: " + newFile.getId(); + LOGE(msg); + throw ProvisionException(msg); + } + files.push_back(newFile); +} + +const FileVector& ProvisionConfig::getFiles() const +{ + return files; +} + +void ProvisionConfig::removeFile(const File& item) +{ + const auto it = std::find(files.begin(), files.end(), item); + if (it == files.end()) { + const std::string msg = "Can't find provision: " + item.getId(); + LOGE(msg); + throw ProvisionException(msg); + } + files.erase(it); +} + + +void ProvisionConfig::addMount(const Mount& newMount) +{ + auto it = std::find(mounts.begin(), mounts.end(), newMount); + if (it != mounts.end()) { + const std::string msg = + "Can't add mount. Provision already exists: " + newMount.getId(); + LOGE(msg); + throw ProvisionException(msg); + } + mounts.push_back(newMount); +} + +const MountVector& ProvisionConfig::getMounts() const +{ + return mounts; +} + +void ProvisionConfig::removeMount(const Mount& item) +{ + const auto it = std::find(mounts.begin(), mounts.end(), item); + if (it == mounts.end()) { + const std::string msg = "Can't find provision: " + item.getId(); + LOGE(msg); + throw ProvisionException(msg); + } + mounts.erase(it); +} + + +void ProvisionConfig::addLink(const Link& newLink) +{ + auto it = std::find(links.begin(), links.end(), newLink); + if (it != links.end()) { + const std::string msg = + "Can't add link. Provision already exists: " + newLink.getId(); + LOGE(msg); + throw ProvisionException(msg); + } + links.push_back(newLink); +} + +const LinkVector& ProvisionConfig::getLinks() const +{ + return links; +} + +void ProvisionConfig::removeLink(const Link& item) +{ + const auto it = std::find(links.begin(), links.end(), item); + if (it == links.end()) { + const std::string msg = "Can't find provision: " + item.getId(); + LOGE(msg); + throw ProvisionException(msg); + } + links.erase(it); +} diff --git a/libs/lxcpp/provision-config.hpp b/libs/lxcpp/provision-config.hpp new file mode 100644 index 0000000..fb9cbc4 --- /dev/null +++ b/libs/lxcpp/provision-config.hpp @@ -0,0 +1,170 @@ +/* + * 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 Maciej Karpiuk (m.karpiuk2@samsung.com) + * @brief Provisioning configuration + */ + +#ifndef LXCPP_PROVISION_CONFIG_HPP +#define LXCPP_PROVISION_CONFIG_HPP + +#include "config/config.hpp" +#include "config/fields.hpp" +#include "config/fields-union.hpp" + +#include +#include +#include + +namespace lxcpp { +namespace provision { + +typedef std::string ProvisionID; + +/** + * Provision configuration items + */ +struct File +{ + enum class Type : int + { + DIRECTORY, + FIFO, + REGULAR + }; + + ProvisionID getId() const + { + return "file " + + path + " " + + std::to_string(static_cast(type)) + " " + + std::to_string(flags) + " " + + std::to_string(mode); + } + + Type type; + std::string path; + std::int32_t flags; + std::int32_t mode; + + CONFIG_REGISTER + ( + type, + path, + flags, + mode + ) + + bool operator==(const File& m) const + { + return ((m.type == type) && (m.path == path) && + (m.flags == flags) && (m.mode == mode)); + } +}; + +struct Mount +{ + ProvisionID getId() const + { + return "mount " + + source + " " + + target + " " + + type + " " + + std::to_string(flags) + " " + + data; + } + + std::string source; + std::string target; + std::string type; + std::int64_t flags; + std::string data; + + CONFIG_REGISTER + ( + source, + target, + type, + flags, + data + ) + + bool operator==(const Mount& m) const + { + return ((m.source == source) && (m.target == target) && (m.type == type) && + (m.flags == flags) && (m.data == data)); + } +}; + +struct Link +{ + ProvisionID getId() const + { + return "link " + source + " " + target; + } + + std::string source; + std::string target; + + CONFIG_REGISTER + ( + source, + target + ) + + bool operator==(const Link& m) const + { + return ((m.source == source) && (m.target == target)); + } +}; +} // namespace provision + +typedef std::vector FileVector; +typedef std::vector MountVector; +typedef std::vector LinkVector; + +struct ProvisionConfig +{ + FileVector files; + MountVector mounts; + LinkVector links; + + void addFile(const provision::File& newFile); + const FileVector& getFiles() const; + void removeFile(const provision::File& item); + + void addMount(const provision::Mount& newMount); + const MountVector& getMounts() const; + void removeMount(const provision::Mount& item); + + void addLink(const provision::Link& newLink); + const LinkVector& getLinks() const; + void removeLink(const provision::Link& item); + + CONFIG_REGISTER + ( + files, + mounts, + links + ) +}; + +} // namespace lxcpp + +#endif // LXCPP_PROVISION_CONFIG_HPP diff --git a/tests/unit_tests/lxcpp/ut-provisioning.cpp b/tests/unit_tests/lxcpp/ut-provisioning.cpp new file mode 100644 index 0000000..d2a535c --- /dev/null +++ b/tests/unit_tests/lxcpp/ut-provisioning.cpp @@ -0,0 +1,164 @@ +/* + * 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 Maciej Karpiuk (m.karpiuk2@samsung.com) + * @brief Unit tests of lxcpp provisioning + */ + +#include "config.hpp" +#include "config/manager.hpp" +#include "lxcpp/lxcpp.hpp" +#include "lxcpp/container.hpp" +#include "lxcpp/container-config.hpp" +#include "lxcpp/provision-config.hpp" +#include "ut.hpp" +#include "utils/scoped-dir.hpp" +#include + +namespace { + +using namespace lxcpp; +using namespace config; +using namespace provision; + +const std::string TEST_DIR = "/tmp/ut-provisioning"; +const std::string ROOT_DIR = TEST_DIR + "/root"; + +struct Fixture { + Fixture() : mTestPath(ROOT_DIR) { + container = std::unique_ptr(createContainer("ProvisioningTester", ROOT_DIR)); + } + ~Fixture() {} + + std::unique_ptr container; + utils::ScopedDir mTestPath; +}; + +} // namespace + + +BOOST_FIXTURE_TEST_SUITE(LxcppProvisioningSuite, Fixture) + +BOOST_AUTO_TEST_CASE(ListProvisionsEmptyContainer) +{ + BOOST_REQUIRE(container->getFiles().size() == 0); + BOOST_REQUIRE(container->getMounts().size() == 0); + BOOST_REQUIRE(container->getLinks().size() == 0); +} + +BOOST_AUTO_TEST_CASE(AddDeclareFile) +{ + container->declareFile(File::Type::FIFO, "path", 0747, 0777); + container->declareFile(File::Type::REGULAR, "path", 0747, 0777); + + std::vector fileList = container->getFiles(); + BOOST_REQUIRE_EQUAL(fileList.size(), 2); + + BOOST_REQUIRE(fileList[0].type == File::Type::FIFO); + BOOST_REQUIRE(fileList[0].path == "path"); + BOOST_REQUIRE(fileList[0].flags == 0747); + BOOST_REQUIRE(fileList[0].mode == 0777); + BOOST_REQUIRE(fileList[1].type == File::Type::REGULAR); + + BOOST_REQUIRE_NO_THROW(container->removeFile(fileList[0])); + BOOST_REQUIRE_EQUAL(container->getFiles().size(), 1); + File dummyFile({File::Type::FIFO, "dummy", 1, 2}); + BOOST_REQUIRE_THROW(container->removeFile(dummyFile), ProvisionException); + BOOST_REQUIRE_NO_THROW(container->removeFile(fileList[1])); + BOOST_REQUIRE_EQUAL(container->getFiles().size(), 0); +} + +BOOST_AUTO_TEST_CASE(AddDeclareMount) +{ + container->declareMount("/fake/path1", "/fake/path2", "tmpfs", 077, "fake"); + container->declareMount("/fake/path2", "/fake/path2", "tmpfs", 077, "fake"); + BOOST_CHECK_THROW(container->declareMount("/fake/path2", "/fake/path2", "tmpfs", 077, "fake"), + ProvisionException); + + std::vector mountList = container->getMounts(); + BOOST_REQUIRE_EQUAL(mountList.size(), 2); + + BOOST_REQUIRE(mountList[0].source == "/fake/path1"); + BOOST_REQUIRE(mountList[0].target == "/fake/path2"); + BOOST_REQUIRE(mountList[0].type == "tmpfs"); + BOOST_REQUIRE(mountList[0].flags == 077); + BOOST_REQUIRE(mountList[0].data == "fake"); + + BOOST_REQUIRE(mountList[1].source == "/fake/path2"); + BOOST_REQUIRE(mountList[1].target == "/fake/path2"); + BOOST_REQUIRE(mountList[1].type == "tmpfs"); + BOOST_REQUIRE(mountList[1].flags == 077); + BOOST_REQUIRE(mountList[1].data == "fake"); + + BOOST_REQUIRE_NO_THROW(container->removeMount(mountList[0])); + BOOST_REQUIRE_EQUAL(container->getMounts().size(), 1); + Mount dummyMount({"a", "b", "c", 1, "d"}); + BOOST_REQUIRE_THROW(container->removeMount(dummyMount), ProvisionException); + BOOST_REQUIRE_NO_THROW(container->removeMount(mountList[1])); + BOOST_REQUIRE_EQUAL(container->getMounts().size(), 0); +} + +BOOST_AUTO_TEST_CASE(AddDeclareLink) +{ + container->declareLink("/fake/path1", "/fake/path2"); + container->declareLink("/fake/path2", "/fake/path2"); + BOOST_CHECK_THROW(container->declareLink("/fake/path2", "/fake/path2"), + ProvisionException); + + std::vector linkList = container->getLinks(); + BOOST_REQUIRE_EQUAL(linkList.size(), 2); + + BOOST_REQUIRE(linkList[0].source == "/fake/path1"); + BOOST_REQUIRE(linkList[0].target == "/fake/path2"); + BOOST_REQUIRE(linkList[1].source == "/fake/path2"); + BOOST_REQUIRE(linkList[1].target == "/fake/path2"); + + BOOST_REQUIRE_NO_THROW(container->removeLink(linkList[0])); + BOOST_REQUIRE_EQUAL(container->getLinks().size(), 1); + Link dummyLink({"a", "b"}); + BOOST_REQUIRE_THROW(container->removeLink(dummyLink), ProvisionException); + BOOST_REQUIRE_NO_THROW(container->removeLink(linkList[1])); + BOOST_REQUIRE_EQUAL(container->getLinks().size(), 0); +} + +BOOST_AUTO_TEST_CASE(ProvisioningConfigSerialization) +{ + std::string tmpConfigFile = "/tmp/fileconfig.conf"; + std::string tmpConfigMount = "/tmp/mountconfig.conf"; + std::string tmpConfigLink = "/tmp/linkconfig.conf"; + + File saved_file ({File::Type::REGULAR, "path", 0747, 0777}); + Mount saved_mount({"/fake/path1", "/fake/path2", "tmpfs", 077, "fake"}); + Link saved_link ({"/fake/path1", "/fake/path2"}); + config::saveToJsonFile(tmpConfigFile, saved_file); + config::saveToJsonFile(tmpConfigMount, saved_mount); + config::saveToJsonFile(tmpConfigLink, saved_link); + + File loaded_file; + Mount loaded_mount; + Link loaded_link; + config::loadFromJsonFile(tmpConfigFile, loaded_file); + config::loadFromJsonFile(tmpConfigMount, loaded_mount); + config::loadFromJsonFile(tmpConfigLink, loaded_link); + BOOST_REQUIRE(saved_file == loaded_file); + BOOST_REQUIRE(saved_mount == loaded_mount); + BOOST_REQUIRE(saved_link == loaded_link); +} + +BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 3547bec83a06ddd27429bc5280690ebc2852732c Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Wed, 30 Sep 2015 11:01:49 +0200 Subject: [PATCH 04/16] Various changes relating to create Fedora (LXDE or KDE) Desktop [Bug/Feature] Various changes relating to create Fedora Desktop [Cause] N/A [Solution] N/A [Verification] Build, run server, run tests. Change-Id: I847ab904012bea962b9961ad70a4e6bed9a69968 --- packaging/vasum.spec | 2 +- server/configs/daemon.conf.in | 7 +- server/configs/templates/fedora-kde-demo.conf | 19 ++ server/configs/templates/fedora-kde-demo.sh | 214 ++++++++++++++++++++ .../configs/templates/fedora-kde-wayland-demo.conf | 19 ++ .../configs/templates/fedora-kde-wayland-demo.sh | 217 +++++++++++++++++++++ server/configs/templates/fedora-lxde-demo.conf | 19 ++ server/configs/templates/fedora-lxde-demo.sh | 213 ++++++++++++++++++++ .../templates/{fedora.conf => fedora-minimal.conf} | 4 +- .../templates/{fedora.sh => fedora-minimal.sh} | 2 +- server/configs/templates/tizen-common-wayland.sh | 2 +- server/configs/templates/ubuntu.sh | 2 +- server/zones-manager-config.hpp | 6 + server/zones-manager.cpp | 29 ++- tests/unit_tests/configs/test-daemon.conf.in | 1 + 15 files changed, 732 insertions(+), 24 deletions(-) create mode 100644 server/configs/templates/fedora-kde-demo.conf create mode 100755 server/configs/templates/fedora-kde-demo.sh create mode 100644 server/configs/templates/fedora-kde-wayland-demo.conf create mode 100755 server/configs/templates/fedora-kde-wayland-demo.sh create mode 100644 server/configs/templates/fedora-lxde-demo.conf create mode 100755 server/configs/templates/fedora-lxde-demo.sh rename server/configs/templates/{fedora.conf => fedora-minimal.conf} (86%) rename server/configs/templates/{fedora.sh => fedora-minimal.sh} (97%) diff --git a/packaging/vasum.spec b/packaging/vasum.spec index 546c782..447bbcf 100644 --- a/packaging/vasum.spec +++ b/packaging/vasum.spec @@ -108,7 +108,7 @@ mkdir -p %{buildroot}/%{_datadir}/zones %if %{platform_type} == "TIZEN" ln -s tizen.conf %{buildroot}/etc/vasum/templates/default.conf %else -ln -s fedora.conf %{buildroot}/etc/vasum/templates/default.conf +ln -s fedora-minimal.conf %{buildroot}/etc/vasum/templates/default.conf %endif %clean diff --git a/server/configs/daemon.conf.in b/server/configs/daemon.conf.in index 96d748f..d107343 100644 --- a/server/configs/daemon.conf.in +++ b/server/configs/daemon.conf.in @@ -7,10 +7,11 @@ "zoneTemplateDir" : "/etc/vasum/templates/", "runMountPointPrefix" : "/var/run/zones", "defaultId" : "", - "availableVTs" : [3, 4, 5, 6], + "hostVT" : 2, + "availableVTs" : [5, 6, 7, 8, 9], "inputConfig" : {"enabled" : false, - "device" : "gpio_keys.6", - "code" : 116, + "device" : "DELL Dell USB Entry Keyboard", + "code" : 1, "numberOfEvents" : 2, "timeWindowMs" : 500}, "proxyCallRules" : [] diff --git a/server/configs/templates/fedora-kde-demo.conf b/server/configs/templates/fedora-kde-demo.conf new file mode 100644 index 0000000..ca47a33 --- /dev/null +++ b/server/configs/templates/fedora-kde-demo.conf @@ -0,0 +1,19 @@ +{ + "zoneTemplate" : "fedora-kde-demo.sh", + "initWithArgs" : [], + "requestedState" : "stopped", + "ipv4Gateway" : "", + "ipv4" : "", + "cpuQuotaForeground" : -1, + "cpuQuotaBackground" : -1, + "privilege" : 10, + "vt" : 0, + "shutdownTimeout" : 10, + "switchToDefaultAfterTimeout" : true, + "runMountPoint" : "~NAME~/run", + "provisions" : [], + "validLinkPrefixes" : [ "/tmp/", + "/run/", + "/opt/usr/data/", + "/opt/usr/dbsapce/" ] +} diff --git a/server/configs/templates/fedora-kde-demo.sh b/server/configs/templates/fedora-kde-demo.sh new file mode 100755 index 0000000..971a102 --- /dev/null +++ b/server/configs/templates/fedora-kde-demo.sh @@ -0,0 +1,214 @@ +#!/bin/bash + +# template script for creating Fedora LXC container +# This script is a wrapper for the lxc-fedora template +# +# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +# +# Contact: Dariusz Michaluk +# +# 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. + +usage() +{ + cat < + [-p|--path=] [--rootfs=] [--vt=] + [--ipv4=] [--ipv4-gateway=] [-h|--help] +Mandatory args: + -n,--name zone name + -p,--path path to zone config files + --rootfs path to zone rootfs +Optional args: + --vt zone virtual terminal + --ipv4 zone IP address + --ipv4-gateway zone gateway + -h,--help print help +EOF + return 0 +} + +options=$(getopt -o hp:n: -l help,rootfs:,path:,vt:,name:,ipv4:,ipv4-gateway: -- "$@") +if [ $? -ne 0 ]; then + usage $(basename $0) + exit 1 +fi +eval set -- "$options" + +while true +do + case "$1" in + -h|--help) usage $(basename $0) && exit 0;; + --rootfs) rootfs=$2; shift 2;; + -p|--path) path=$2; shift 2;; + --vt) vt=$2; shift 2;; + -n|--name) name=$2; shift 2;; + --ipv4) ipv4=$2; shift 2;; + --ipv4-gateway) ipv4_gateway=$2; shift 2;; + --) shift 1; break ;; + *) break ;; + esac +done + +if [ "$(id -u)" != "0" ]; then + echo "This script should be run as 'root'" + exit 1 +fi + +if [ -z $name ]; then + echo "Zone name must be given" + exit 1 +fi + +if [ -z "$path" ]; then + echo "'path' parameter is required" + exit 1 +fi + +if [ -z "$rootfs" ]; then + echo "'rootfs' parameter is required" + exit 1 +fi + +/usr/share/lxc/templates/lxc-fedora --name="$name" --path="$path" --rootfs="$rootfs" + +if [ "$vt" -gt "0" ]; then + echo "Setup Desktop" + chroot $rootfs yum -y --nogpgcheck groupinstall "KDE Plasma Workspaces" + chroot $rootfs yum -y --nogpgcheck groupinstall "Firefox Web Browser" + chroot $rootfs yum -y --nogpgcheck install openarena + chroot $rootfs yum -y --nogpgcheck install http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm \ + http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm + chroot $rootfs yum -y --nogpgcheck install gstreamer1-libav gstreamer1-vaapi gstreamer1-plugins-{good,good-extras,ugly} + chroot $rootfs yum -y remove pulseaudio + chroot $rootfs passwd -d root + + cat <>${rootfs}/etc/X11/xorg.conf +Section "ServerFlags" + Option "AutoAddDevices" "false" +EndSection +Section "InputDevice" + Identifier "event0" + Driver "evdev" + Option "Device" "/dev/input/event0" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event1" + Driver "evdev" + Option "Device" "/dev/input/event1" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event10" + Driver "evdev" + Option "Device" "/dev/input/event10" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event2" + Driver "evdev" + Option "Device" "/dev/input/event2" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event3" + Driver "evdev" + Option "Device" "/dev/input/event3" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event4" + Driver "evdev" + Option "Device" "/dev/input/event4" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event5" + Driver "evdev" + Option "Device" "/dev/input/event5" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event6" + Driver "evdev" + Option "Device" "/dev/input/event6" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event7" + Driver "evdev" + Option "Device" "/dev/input/event7" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event8" + Driver "evdev" + Option "Device" "/dev/input/event8" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event9" + Driver "evdev" + Option "Device" "/dev/input/event9" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "mice" + Driver "evdev" + Option "Device" "/dev/input/mice" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "mouse0" + Driver "evdev" + Option "Device" "/dev/input/mouse0" + Option "AutoServerLayout" "true" +EndSection +EOF + + chroot ${rootfs} rm -rf /etc/systemd/system/display-manager.service + cat <${rootfs}/etc/systemd/system/display-manager.service +[Unit] +Description=Start Desktop + +[Service] +ExecStartPre=/bin/mknod /dev/tty${vt} c 0x4 0x${vt} +ExecStart=/bin/startx -- :0 vt${vt} + +[Install] +WantedBy=graphical.target +EOF + + chroot $rootfs sed -i 's/configDir=${HOME}/export HOME=\/root; configDir=${HOME}/g' /bin/startkde + chroot $rootfs ln -sf /dev/null /etc/systemd/system/initial-setup-graphical.service + chroot $rootfs ln -sf /usr/lib/systemd/system/graphical.target /etc/systemd/system/default.target + chroot $rootfs mkdir -p /etc/systemd/system/graphical.target.wants + chroot $rootfs ln -sf /etc/systemd/system/display-manager.service /etc/systemd/system/graphical.target.wants/display-manager.service + + cat <>${path}/config +lxc.mount.entry = /dev/dri dev/dri none bind,optional,create=dir +lxc.mount.entry = /dev/input dev/input none bind,optional,create=dir +lxc.mount.entry = /dev/snd dev/snd none bind,optional,create=dir +### /dev/dri/* +lxc.cgroup.devices.allow = c 226:* rwm +### /dev/input/* +lxc.cgroup.devices.allow = c 13:* rwm +### /dev/snd/* +lxc.cgroup.devices.allow = c 116:* rwm +### /dev/tty* +lxc.cgroup.devices.allow = c 4:* rwm +EOF + +fi diff --git a/server/configs/templates/fedora-kde-wayland-demo.conf b/server/configs/templates/fedora-kde-wayland-demo.conf new file mode 100644 index 0000000..2131567 --- /dev/null +++ b/server/configs/templates/fedora-kde-wayland-demo.conf @@ -0,0 +1,19 @@ +{ + "zoneTemplate" : "fedora-kde-wayland-demo.sh", + "initWithArgs" : [], + "requestedState" : "stopped", + "ipv4Gateway" : "", + "ipv4" : "", + "cpuQuotaForeground" : -1, + "cpuQuotaBackground" : -1, + "privilege" : 10, + "vt" : 0, + "shutdownTimeout" : 10, + "switchToDefaultAfterTimeout" : true, + "runMountPoint" : "~NAME~/run", + "provisions" : [], + "validLinkPrefixes" : [ "/tmp/", + "/run/", + "/opt/usr/data/", + "/opt/usr/dbsapce/" ] +} diff --git a/server/configs/templates/fedora-kde-wayland-demo.sh b/server/configs/templates/fedora-kde-wayland-demo.sh new file mode 100755 index 0000000..f915a9f --- /dev/null +++ b/server/configs/templates/fedora-kde-wayland-demo.sh @@ -0,0 +1,217 @@ +#!/bin/bash + +# template script for creating Fedora LXC container +# This script is a wrapper for the lxc-fedora template +# +# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +# +# Contact: Dariusz Michaluk +# +# 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. + +usage() +{ + cat < + [-p|--path=] [--rootfs=] [--vt=] + [--ipv4=] [--ipv4-gateway=] [-h|--help] +Mandatory args: + -n,--name zone name + -p,--path path to zone config files + --rootfs path to zone rootfs +Optional args: + --vt zone virtual terminal + --ipv4 zone IP address + --ipv4-gateway zone gateway + -h,--help print help +EOF + return 0 +} + +options=$(getopt -o hp:n: -l help,rootfs:,path:,vt:,name:,ipv4:,ipv4-gateway: -- "$@") +if [ $? -ne 0 ]; then + usage $(basename $0) + exit 1 +fi +eval set -- "$options" + +while true +do + case "$1" in + -h|--help) usage $(basename $0) && exit 0;; + --rootfs) rootfs=$2; shift 2;; + -p|--path) path=$2; shift 2;; + --vt) vt=$2; shift 2;; + -n|--name) name=$2; shift 2;; + --ipv4) ipv4=$2; shift 2;; + --ipv4-gateway) ipv4_gateway=$2; shift 2;; + --) shift 1; break ;; + *) break ;; + esac +done + +if [ "$(id -u)" != "0" ]; then + echo "This script should be run as 'root'" + exit 1 +fi + +if [ -z $name ]; then + echo "Zone name must be given" + exit 1 +fi + +if [ -z "$path" ]; then + echo "'path' parameter is required" + exit 1 +fi + +if [ -z "$rootfs" ]; then + echo "'rootfs' parameter is required" + exit 1 +fi + +/usr/share/lxc/templates/lxc-fedora --name="$name" --path="$path" --rootfs="$rootfs" + +if [ "$vt" -gt "0" ]; then + echo "Setup Desktop" + chroot $rootfs yum -y --nogpgcheck groupinstall "KDE Plasma Workspaces" + chroot $rootfs yum -y --nogpgcheck install kwin-wayland qt5-qtwayland xorg-x11-server-Xwayland + chroot $rootfs yum -y --nogpgcheck groupinstall "Firefox Web Browser" + chroot $rootfs yum -y remove pulseaudio + chroot $rootfs passwd -d root + + cat <>${rootfs}/etc/X11/xorg.conf +Section "ServerFlags" + Option "AutoAddDevices" "false" +EndSection +Section "InputDevice" + Identifier "event0" + Driver "evdev" + Option "Device" "/dev/input/event0" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event1" + Driver "evdev" + Option "Device" "/dev/input/event1" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event10" + Driver "evdev" + Option "Device" "/dev/input/event10" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event2" + Driver "evdev" + Option "Device" "/dev/input/event2" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event3" + Driver "evdev" + Option "Device" "/dev/input/event3" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event4" + Driver "evdev" + Option "Device" "/dev/input/event4" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event5" + Driver "evdev" + Option "Device" "/dev/input/event5" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event6" + Driver "evdev" + Option "Device" "/dev/input/event6" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event7" + Driver "evdev" + Option "Device" "/dev/input/event7" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event8" + Driver "evdev" + Option "Device" "/dev/input/event8" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event9" + Driver "evdev" + Option "Device" "/dev/input/event9" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "mice" + Driver "evdev" + Option "Device" "/dev/input/mice" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "mouse0" + Driver "evdev" + Option "Device" "/dev/input/mouse0" + Option "AutoServerLayout" "true" +EndSection +EOF + + chroot ${rootfs} rm -rf /etc/systemd/system/display-manager.service + cat <${rootfs}/etc/systemd/system/display-manager.service +[Unit] +Description=Start Desktop + +[Service] +ExecStartPre=/bin/mknod /dev/tty${vt} c 0x4 0x${vt} +ExecStart=/bin/startx -- :0 vt${vt} + +[Install] +WantedBy=graphical.target +EOF + + chroot $rootfs rm -rf /bin/startkde + chroot $rootfs cp /bin/startplasmacompositor /bin/startkde + chroot $rootfs sed -i 's/--libinput/--width=1920 --height=1080 --libinput/g' /bin/startkde + chroot $rootfs sed -i 's/\/usr\/libexec\/startplasma/\/bin\/plasmashell/g' /bin/startkde + chroot $rootfs sed -i 's/configDir=${HOME}/export XDG_RUNTIME_DIR=\/tmp; configDir=${HOME}/g' /bin/startkde + chroot $rootfs sed -i 's/X-KDE-Kded-autoload=true/X-KDE-Kded-autoload=false/g' /usr/share/kservices5/kded/*.desktop + + chroot $rootfs ln -sf /dev/null /etc/systemd/system/initial-setup-graphical.service + chroot $rootfs ln -sf /usr/lib/systemd/system/graphical.target /etc/systemd/system/default.target + chroot $rootfs mkdir -p /etc/systemd/system/graphical.target.wants + chroot $rootfs ln -sf /etc/systemd/system/display-manager.service /etc/systemd/system/graphical.target.wants/display-manager.service + + cat <>${path}/config +lxc.mount.entry = /dev/dri dev/dri none bind,optional,create=dir +lxc.mount.entry = /dev/input dev/input none bind,optional,create=dir +lxc.mount.entry = /dev/snd dev/snd none bind,optional,create=dir +### /dev/dri/* +lxc.cgroup.devices.allow = c 226:* rwm +### /dev/input/* +lxc.cgroup.devices.allow = c 13:* rwm +### /dev/snd/* +lxc.cgroup.devices.allow = c 116:* rwm +### /dev/tty* +lxc.cgroup.devices.allow = c 4:* rwm +EOF + +fi diff --git a/server/configs/templates/fedora-lxde-demo.conf b/server/configs/templates/fedora-lxde-demo.conf new file mode 100644 index 0000000..847bb4d --- /dev/null +++ b/server/configs/templates/fedora-lxde-demo.conf @@ -0,0 +1,19 @@ +{ + "zoneTemplate" : "fedora-lxde-demo.sh", + "initWithArgs" : [], + "requestedState" : "stopped", + "ipv4Gateway" : "", + "ipv4" : "", + "cpuQuotaForeground" : -1, + "cpuQuotaBackground" : -1, + "privilege" : 10, + "vt" : 0, + "shutdownTimeout" : 10, + "switchToDefaultAfterTimeout" : true, + "runMountPoint" : "~NAME~/run", + "provisions" : [], + "validLinkPrefixes" : [ "/tmp/", + "/run/", + "/opt/usr/data/", + "/opt/usr/dbsapce/" ] +} diff --git a/server/configs/templates/fedora-lxde-demo.sh b/server/configs/templates/fedora-lxde-demo.sh new file mode 100755 index 0000000..7bd4e02 --- /dev/null +++ b/server/configs/templates/fedora-lxde-demo.sh @@ -0,0 +1,213 @@ +#!/bin/bash + +# template script for creating Fedora LXC container +# This script is a wrapper for the lxc-fedora template +# +# Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +# +# Contact: Dariusz Michaluk +# +# 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. + +usage() +{ + cat < + [-p|--path=] [--rootfs=] [--vt=] + [--ipv4=] [--ipv4-gateway=] [-h|--help] +Mandatory args: + -n,--name zone name + -p,--path path to zone config files + --rootfs path to zone rootfs +Optional args: + --vt zone virtual terminal + --ipv4 zone IP address + --ipv4-gateway zone gateway + -h,--help print help +EOF + return 0 +} + +options=$(getopt -o hp:n: -l help,rootfs:,path:,vt:,name:,ipv4:,ipv4-gateway: -- "$@") +if [ $? -ne 0 ]; then + usage $(basename $0) + exit 1 +fi +eval set -- "$options" + +while true +do + case "$1" in + -h|--help) usage $(basename $0) && exit 0;; + --rootfs) rootfs=$2; shift 2;; + -p|--path) path=$2; shift 2;; + --vt) vt=$2; shift 2;; + -n|--name) name=$2; shift 2;; + --ipv4) ipv4=$2; shift 2;; + --ipv4-gateway) ipv4_gateway=$2; shift 2;; + --) shift 1; break ;; + *) break ;; + esac +done + +if [ "$(id -u)" != "0" ]; then + echo "This script should be run as 'root'" + exit 1 +fi + +if [ -z $name ]; then + echo "Zone name must be given" + exit 1 +fi + +if [ -z "$path" ]; then + echo "'path' parameter is required" + exit 1 +fi + +if [ -z "$rootfs" ]; then + echo "'rootfs' parameter is required" + exit 1 +fi + +/usr/share/lxc/templates/lxc-fedora --name="$name" --path="$path" --rootfs="$rootfs" + +if [ "$vt" -gt "0" ]; then + echo "Setup Desktop" + chroot $rootfs yum -y --nogpgcheck groupinstall "LXDE Desktop" + chroot $rootfs yum -y --nogpgcheck groupinstall "Firefox Web Browser" + chroot $rootfs yum -y --nogpgcheck install openarena + chroot $rootfs yum -y --nogpgcheck install http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-$(rpm -E %fedora).noarch.rpm \ + http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-$(rpm -E %fedora).noarch.rpm + chroot $rootfs yum -y --nogpgcheck install gstreamer1-libav gstreamer1-vaapi gstreamer1-plugins-{good,good-extras,ugly} + chroot $rootfs yum -y remove pulseaudio + chroot $rootfs passwd -d root + + cat <>${rootfs}/etc/X11/xorg.conf +Section "ServerFlags" + Option "AutoAddDevices" "false" +EndSection +Section "InputDevice" + Identifier "event0" + Driver "evdev" + Option "Device" "/dev/input/event0" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event1" + Driver "evdev" + Option "Device" "/dev/input/event1" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event10" + Driver "evdev" + Option "Device" "/dev/input/event10" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event2" + Driver "evdev" + Option "Device" "/dev/input/event2" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event3" + Driver "evdev" + Option "Device" "/dev/input/event3" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event4" + Driver "evdev" + Option "Device" "/dev/input/event4" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event5" + Driver "evdev" + Option "Device" "/dev/input/event5" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event6" + Driver "evdev" + Option "Device" "/dev/input/event6" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event7" + Driver "evdev" + Option "Device" "/dev/input/event7" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event8" + Driver "evdev" + Option "Device" "/dev/input/event8" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "event9" + Driver "evdev" + Option "Device" "/dev/input/event9" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "mice" + Driver "evdev" + Option "Device" "/dev/input/mice" + Option "AutoServerLayout" "true" +EndSection +Section "InputDevice" + Identifier "mouse0" + Driver "evdev" + Option "Device" "/dev/input/mouse0" + Option "AutoServerLayout" "true" +EndSection +EOF + + chroot ${rootfs} rm -rf /etc/systemd/system/display-manager.service + cat <${rootfs}/etc/systemd/system/display-manager.service +[Unit] +Description=Start Desktop + +[Service] +ExecStartPre=/bin/mknod /dev/tty${vt} c 0x4 0x${vt} +ExecStart=/bin/startx -- :0 vt${vt} + +[Install] +WantedBy=graphical.target +EOF + + chroot $rootfs ln -sf /dev/null /etc/systemd/system/initial-setup-graphical.service + chroot $rootfs ln -sf /usr/lib/systemd/system/graphical.target /etc/systemd/system/default.target + chroot $rootfs mkdir -p /etc/systemd/system/graphical.target.wants + chroot $rootfs ln -sf /etc/systemd/system/display-manager.service /etc/systemd/system/graphical.target.wants/display-manager.service + + cat <>${path}/config +lxc.mount.entry = /dev/dri dev/dri none bind,optional,create=dir +lxc.mount.entry = /dev/input dev/input none bind,optional,create=dir +lxc.mount.entry = /dev/snd dev/snd none bind,optional,create=dir +### /dev/dri/* +lxc.cgroup.devices.allow = c 226:* rwm +### /dev/input/* +lxc.cgroup.devices.allow = c 13:* rwm +### /dev/snd/* +lxc.cgroup.devices.allow = c 116:* rwm +### /dev/tty* +lxc.cgroup.devices.allow = c 4:* rwm +EOF + +fi diff --git a/server/configs/templates/fedora.conf b/server/configs/templates/fedora-minimal.conf similarity index 86% rename from server/configs/templates/fedora.conf rename to server/configs/templates/fedora-minimal.conf index 12e0d2a..e8271ec 100644 --- a/server/configs/templates/fedora.conf +++ b/server/configs/templates/fedora-minimal.conf @@ -1,11 +1,11 @@ { - "zoneTemplate" : "fedora.sh", + "zoneTemplate" : "fedora-minimal.sh", "initWithArgs" : [], "requestedState" : "stopped", "ipv4Gateway" : "", "ipv4" : "", "cpuQuotaForeground" : -1, - "cpuQuotaBackground" : 1000, + "cpuQuotaBackground" : -1, "privilege" : 10, "vt" : -1, "shutdownTimeout" : 10, diff --git a/server/configs/templates/fedora.sh b/server/configs/templates/fedora-minimal.sh similarity index 97% rename from server/configs/templates/fedora.sh rename to server/configs/templates/fedora-minimal.sh index dc4db3b..604b08c 100755 --- a/server/configs/templates/fedora.sh +++ b/server/configs/templates/fedora-minimal.sh @@ -49,7 +49,7 @@ eval set -- "$options" while true do case "$1" in - -h|--help) usage $0 && exit 0;; + -h|--help) usage $(basename $0) && exit 0;; --rootfs) rootfs=$2; shift 2;; -p|--path) path=$2; shift 2;; --vt) vt=$2; shift 2;; diff --git a/server/configs/templates/tizen-common-wayland.sh b/server/configs/templates/tizen-common-wayland.sh index 05cca6d..4f7c407 100755 --- a/server/configs/templates/tizen-common-wayland.sh +++ b/server/configs/templates/tizen-common-wayland.sh @@ -48,7 +48,7 @@ eval set -- "$options" while true do case "$1" in - -h|--help) usage $0 && exit 0;; + -h|--help) usage $(basename $0) && exit 0;; --rootfs) rootfs=$2; shift 2;; -p|--path) path=$2; shift 2;; --vt) vt=$2; shift 2;; diff --git a/server/configs/templates/ubuntu.sh b/server/configs/templates/ubuntu.sh index edcf649..1253b4c 100755 --- a/server/configs/templates/ubuntu.sh +++ b/server/configs/templates/ubuntu.sh @@ -49,7 +49,7 @@ eval set -- "$options" while true do case "$1" in - -h|--help) usage $0 && exit 0;; + -h|--help) usage $(basename $0) && exit 0;; --rootfs) rootfs=$2; shift 2;; -p|--path) path=$2; shift 2;; --vt) vt=$2; shift 2;; diff --git a/server/zones-manager-config.hpp b/server/zones-manager-config.hpp index e300e75..cd7d4c0 100644 --- a/server/zones-manager-config.hpp +++ b/server/zones-manager-config.hpp @@ -65,6 +65,11 @@ struct ZonesManagerConfig { std::string zoneTemplateDir; /** + * Host VT + */ + int hostVT; + + /** * VTs available for zones */ std::vector availableVTs; @@ -91,6 +96,7 @@ struct ZonesManagerConfig { cleanUpZonesPath, zoneImagePath, zoneTemplateDir, + hostVT, availableVTs, inputConfig, runMountPointPrefix, diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index baf3ed1..7a2bf11 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -37,6 +37,7 @@ #include "utils/fs.hpp" #include "utils/img.hpp" #include "utils/environment.hpp" +#include "utils/vt.hpp" #include "api/messages.hpp" #include @@ -392,8 +393,7 @@ void ZonesManager::focusInternal(Zones::iterator iter) if (iter == mZones.end()) { if (!mActiveZoneId.empty()) { LOGI("Focus to: host"); - // give back the focus to the host - // TODO switch to host vt + utils::activateVT(mConfig.hostVT); mActiveZoneId.clear(); } return; @@ -519,10 +519,7 @@ ZonesManager::Zones::iterator ZonesManager::getRunningForegroundZoneIterator() } auto iter = findZone(mActiveZoneId); if (!get(iter).isRunning()) { - // Can zone change its state by itself? - // Maybe when it is shut down by itself? TODO check it LOGW("Active zone " << mActiveZoneId << " is not running any more!"); - assert(false); return mZones.end(); } return iter; @@ -1149,21 +1146,23 @@ void ZonesManager::generateNewConfig(const std::string& id, ZONE_NAME_REGEX, id); - if (dynamicConfig.vt >= 0 && !dynamicConfig.ipv4Gateway.empty() && !dynamicConfig.ipv4.empty()) { + if (dynamicConfig.vt >= 0) { // generate first free VT number const int freeVT = getVTForNewZone(); LOGD("VT number: " << freeVT); dynamicConfig.vt = freeVT; - // generate third IP octet for network config - std::string thirdOctetStr = std::to_string(ZONE_IP_BASE_THIRD_OCTET + freeVT); - LOGD("IP third octet: " << thirdOctetStr); - dynamicConfig.ipv4Gateway = boost::regex_replace(dynamicConfig.ipv4Gateway, - ZONE_IP_THIRD_OCTET_REGEX, - thirdOctetStr); - dynamicConfig.ipv4 = boost::regex_replace(dynamicConfig.ipv4, - ZONE_IP_THIRD_OCTET_REGEX, - thirdOctetStr); + if (!dynamicConfig.ipv4Gateway.empty() && !dynamicConfig.ipv4.empty()) { + // generate third IP octet for network config + std::string thirdOctetStr = std::to_string(ZONE_IP_BASE_THIRD_OCTET + freeVT); + LOGD("IP third octet: " << thirdOctetStr); + dynamicConfig.ipv4Gateway = boost::regex_replace(dynamicConfig.ipv4Gateway, + ZONE_IP_THIRD_OCTET_REGEX, + thirdOctetStr); + dynamicConfig.ipv4 = boost::regex_replace(dynamicConfig.ipv4, + ZONE_IP_THIRD_OCTET_REGEX, + thirdOctetStr); + } } // save dynamic config diff --git a/tests/unit_tests/configs/test-daemon.conf.in b/tests/unit_tests/configs/test-daemon.conf.in index 66ca69f..2ed411b 100644 --- a/tests/unit_tests/configs/test-daemon.conf.in +++ b/tests/unit_tests/configs/test-daemon.conf.in @@ -7,6 +7,7 @@ "zoneTemplateDir" : "@VSM_TEST_CONFIG_INSTALL_DIR@/templates/", "runMountPointPrefix" : "", "defaultId" : "", + "hostVT" : 2, "availableVTs" : [], "inputConfig" : {"enabled" : false, "device" : "gpio-keys.4", -- 2.7.4 From d56d6393f67cd587e0d3e8c18a57a4f49a701c2c Mon Sep 17 00:00:00 2001 From: Jan Olszak Date: Mon, 19 Oct 2015 14:49:45 +0200 Subject: [PATCH 05/16] common: Inotify implementation [Feature] Asynchronous file system events [Cause] N/A [Solution] N/A [Verification] Build, install and run tests Change-Id: I53b1d75026550cf3563dce7fb1ea50eede4fb5cb --- common/utils/eventfd.hpp | 2 +- common/utils/fs.cpp | 53 +++++++++--- common/utils/fs.hpp | 5 ++ common/utils/inotify.cpp | 151 ++++++++++++++++++++++++++++++++++ common/utils/inotify.hpp | 88 ++++++++++++++++++++ common/utils/paths.hpp | 3 +- common/utils/signalfd.hpp | 4 +- tests/unit_tests/utils/ut-inotify.cpp | 150 +++++++++++++++++++++++++++++++++ 8 files changed, 439 insertions(+), 17 deletions(-) create mode 100644 common/utils/inotify.cpp create mode 100644 common/utils/inotify.hpp create mode 100644 tests/unit_tests/utils/ut-inotify.cpp diff --git a/common/utils/eventfd.hpp b/common/utils/eventfd.hpp index f49bbff..698847d 100644 --- a/common/utils/eventfd.hpp +++ b/common/utils/eventfd.hpp @@ -31,7 +31,7 @@ class EventFD { public: EventFD(); - ~EventFD(); + virtual ~EventFD(); EventFD(const EventFD& eventfd) = delete; EventFD& operator=(const EventFD&) = delete; diff --git a/common/utils/fs.cpp b/common/utils/fs.cpp index a7a979a..62e6c37 100644 --- a/common/utils/fs.cpp +++ b/common/utils/fs.cpp @@ -135,6 +135,35 @@ bool isCharDevice(const std::string& path) return ::stat(path.c_str(), &s) == 0 && S_IFCHR == (s.st_mode & S_IFMT); } +void assertIsDir(const std::string& path) +{ + if (path.empty()) { + const std::string msg = "Empty path"; + LOGE(msg); + throw UtilsException(msg); + } + + struct stat s; + if (::stat(path.c_str(), &s)) { + const std::string msg = "Error in stat() " + path + ": " + getSystemErrorMessage(); + LOGE(msg); + throw UtilsException(msg); + } + + if(!(s.st_mode & S_IFDIR)) { + const std::string msg = "Not a directory"; + LOGE(msg); + throw UtilsException(msg); + } + + if(::access(path.c_str(), X_OK) < 0) { + const std::string msg = "Not a traversable directory"; + LOGE(msg); + throw UtilsException(msg); + } +} + + namespace { // NOTE: Should be the same as in systemd/src/core/mount-setup.c const std::string RUN_MOUNT_POINT_OPTIONS = "mode=755,smackfstransmute=System::Run"; @@ -270,8 +299,8 @@ bool copyDirContentsRec(const boost::filesystem::path& src, const boost::filesys { try { for (fs::directory_iterator file(src); - file != fs::directory_iterator(); - ++file) { + file != fs::directory_iterator(); + ++file) { fs::path current(file->path()); fs::path destination = dst / current.filename(); @@ -400,7 +429,7 @@ bool createDirs(const std::string& path, mode_t mode) fs::remove(*iter, errorCode); if (errorCode) { LOGE("Error during cleaning: dir: " << *iter - << ", msg: " << errorCode.message()); + << ", msg: " << errorCode.message()); } } return false; @@ -455,12 +484,12 @@ bool createFile(const std::string& path, int flags, mode_t mode) bool createFifo(const std::string& path, mode_t mode) { - int ret = ::mkfifo(path.c_str(), mode); - if (ret < 0) { - LOGE("Failed to make fifo: path=host:" << path); - return false; - } - return true; + int ret = ::mkfifo(path.c_str(), mode); + if (ret < 0) { + LOGE("Failed to make fifo: path=host:" << path); + return false; + } + return true; } bool copyFile(const std::string& src, const std::string& dest) @@ -510,9 +539,9 @@ bool createLink(const std::string& src, const std::string& dest) bool retSmack = copySmackLabel(src, dest); if (!retSmack) { LOGE("Failed to copy smack label: path=host:" - << src - << ", path=host:" - << dest); + << src + << ", path=host:" + << dest); boost::system::error_code ec; fs::remove(dest, ec); if (!ec) { diff --git a/common/utils/fs.hpp b/common/utils/fs.hpp index bff2e70..2237450 100644 --- a/common/utils/fs.hpp +++ b/common/utils/fs.hpp @@ -65,6 +65,11 @@ bool removeFile(const std::string& path); bool isCharDevice(const std::string& path); /** + * Checks if a path exists and points to a directory + */ +void assertIsDir(const std::string& path); + +/** * List all (including '.' and '..' entries) dir entries */ bool listDir(const std::string& path, std::vector& files); diff --git a/common/utils/inotify.cpp b/common/utils/inotify.cpp new file mode 100644 index 0000000..a94d95b --- /dev/null +++ b/common/utils/inotify.cpp @@ -0,0 +1,151 @@ +/* +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +* +* Contact: Jan Olszak +* +* 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 Inotify wrapper + */ + +#include "utils/inotify.hpp" +#include "utils/paths.hpp" +#include "utils/fs.hpp" +#include "utils/fd-utils.hpp" +#include "utils/exception.hpp" + +#include "logger/logger.hpp" + +#include + +#include + + +namespace utils { + +Inotify::Inotify(ipc::epoll::EventPoll& eventPoll) + :mEventPoll(eventPoll) +{ + mFD = ::inotify_init1(IN_CLOEXEC); + if (mFD == -1) { + const std::string msg = "Error in inotify_init1: " + getSystemErrorMessage(); + LOGE(msg); + throw UtilsException(msg); + } + + mEventPoll.addFD(mFD, EPOLLIN, std::bind(&Inotify::handleInternal, this)); +} + +Inotify::~Inotify() +{ + Lock lock(mMutex); + + for(const auto& handler: mHandlers) { + if (-1 == ::inotify_rm_watch(mFD, handler.watchID)) { + LOGE("Error in inotify_rm_watch: " + getSystemErrorMessage()); + } + } + mEventPoll.removeFD(mFD); +} + +int Inotify::getFD() const +{ + return mFD; +} + +void Inotify::setHandler(const std::string& path, + const uint32_t eventMask, + const Callback&& callback) +{ + Lock lock(mMutex); + + removeHandlerInternal(path); + + int watchID = ::inotify_add_watch(mFD, path.c_str(), eventMask); + if (-1 == watchID) { + const std::string msg = "Error in inotify_add_watch: " + getSystemErrorMessage(); + LOGE(msg); + throw UtilsException(msg); + } + + mHandlers.push_back({path, watchID, callback}); +} + +void Inotify::removeHandlerInternal(const std::string& path) +{ + // Find the corresponding handler's data + auto it = std::find_if(mHandlers.begin(), mHandlers.end(), [&path](const Handler& h) { + return path == h.path; + }); + + if (it == mHandlers.end()) { + return; + } + + // Unwatch the path + if (-1 == ::inotify_rm_watch(mFD, it->watchID)) { + const std::string msg = "Error in inotify_rm_watch: " + getSystemErrorMessage(); + LOGE(msg); + throw UtilsException(msg); + } + + mHandlers.erase(it); +} + +void Inotify::removeHandler(const std::string& path) +{ + Lock lock(mMutex); + removeHandlerInternal(path); +} + +void Inotify::handleInternal() +{ + Lock lock(mMutex); + + // Get how much data is awaiting + unsigned int bufferSize; + utils::ioctl(mFD, FIONREAD, &bufferSize); + + // Read all events into a buffer + std::vector buffer(bufferSize); + utils::read(mFD, buffer.data(), bufferSize); + + // Handle all events + unsigned int offset = 0; + while (offset < bufferSize) { + struct ::inotify_event *event = reinterpret_cast(&buffer[offset]); + offset = offset + sizeof(inotify_event) + event->len; + + if(event->mask & IN_IGNORED) { + // Watch was removed - ignore + continue; + } + + auto it = std::find_if(mHandlers.begin(), mHandlers.end(), [event](const Handler& h) { + return event->wd == h.watchID; + }); + if (it == mHandlers.end()) { + // Meantime the callback was deleted by another callback + LOGE("No callback for file: " << event->name); + continue; + } + + it->call(event->name, event->mask); + } +} + +} // namespace utils diff --git a/common/utils/inotify.hpp b/common/utils/inotify.hpp new file mode 100644 index 0000000..15c90b8 --- /dev/null +++ b/common/utils/inotify.hpp @@ -0,0 +1,88 @@ +/* +* Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +* +* Contact: Jan Olszak +* +* 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 Inotify wrapper + */ + +#ifndef COMMON_UTILS_INOTIFY_HPP +#define COMMON_UTILS_INOTIFY_HPP + +#include "ipc/epoll/event-poll.hpp" + +#include +#include +#include + +#include + + +namespace utils { + +/** + * Inotify monitors a directory and when a specified file or folder + * is created or deleted it calls a corresponding handler. + */ +class Inotify { +public: + typedef std::function Callback; + + Inotify(ipc::epoll::EventPoll& eventPoll); + virtual ~Inotify(); + + Inotify(const Inotify&) = delete; + Inotify& operator=(const Inotify&) = delete; + + /** + * Add a callback for a specified path + */ + void setHandler(const std::string& path, const uint32_t eventMask, const Callback&& callback); + + /** + * Stop watching the path + */ + void removeHandler(const std::string& path); + + /** + * @return inotify file descriptor + */ + int getFD() const; + +private: + struct Handler { + std::string path; + int watchID; + Callback call; + }; + + typedef std::lock_guard Lock; + std::recursive_mutex mMutex; + + int mFD; + ipc::epoll::EventPoll& mEventPoll; + std::vector mHandlers; + + void handleInternal(); + void removeHandlerInternal(const std::string& path); +}; + +} // namespace utils + +#endif // COMMON_UTILS_INOTIFY_HPP diff --git a/common/utils/paths.hpp b/common/utils/paths.hpp index 26ebde6..2757130 100644 --- a/common/utils/paths.hpp +++ b/common/utils/paths.hpp @@ -87,7 +87,7 @@ inline void removeTrailingSlash(std::string& path) } } -} // anonymous namespace +} // namespace /* * Gets the dir name of a file path, analogous to dirname(1) @@ -118,7 +118,6 @@ inline std::string getAbsolutePath(const std::string& path, const std::string& b } } - } // namespace utils diff --git a/common/utils/signalfd.hpp b/common/utils/signalfd.hpp index cc72ed9..ea62e70 100644 --- a/common/utils/signalfd.hpp +++ b/common/utils/signalfd.hpp @@ -19,7 +19,7 @@ /** * @file * @author Jan Olszak (j.olszak@samsung.com) - * @brief Eventfd wrapper + * @brief Signalfd wrapper */ #ifndef COMMON_UTILS_SIGNALFD_HPP @@ -49,7 +49,7 @@ public: typedef std::function Callback; SignalFD(ipc::epoll::EventPoll& eventPoll); - ~SignalFD(); + virtual ~SignalFD(); SignalFD(const SignalFD& signalfd) = delete; SignalFD& operator=(const SignalFD&) = delete; diff --git a/tests/unit_tests/utils/ut-inotify.cpp b/tests/unit_tests/utils/ut-inotify.cpp new file mode 100644 index 0000000..31b9e54 --- /dev/null +++ b/tests/unit_tests/utils/ut-inotify.cpp @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved + * + * Contact: Jan Olszak + * + * 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 Inotify + */ + +#include "config.hpp" +#include "ut.hpp" + +#include "utils/inotify.hpp" +#include "utils/fs.hpp" +#include "utils/scoped-dir.hpp" +#include "utils/value-latch.hpp" + +#include "logger/logger.hpp" + +#include "ipc/epoll/event-poll.hpp" +#include "ipc/epoll/thread-dispatcher.hpp" + +#include + +using namespace utils; +namespace fs = boost::filesystem; + +namespace { + +const std::string TEST_DIR = "/tmp/ut-inotify/"; +const std::string DIR_NAME = "dir"; +const std::string FILE_NAME = "file.txt"; + +const std::string DIR_PATH = TEST_DIR + DIR_NAME; +const std::string FILE_PATH = TEST_DIR + FILE_NAME; + + +struct Fixture { + utils::ScopedDir mTestDir; + + Fixture() + :mTestDir(TEST_DIR) + {} +}; + +} // namespace + + +BOOST_FIXTURE_TEST_SUITE(InotifySuite, Fixture) + +BOOST_AUTO_TEST_CASE(ConstructorDesctructor) +{ + ipc::epoll::EventPoll poll; + Inotify i(poll); +} + +BOOST_AUTO_TEST_CASE(CreateDeleteFileHandler) +{ + ipc::epoll::ThreadDispatcher dispatcher; + Inotify i(dispatcher.getPoll()); + + // Callback on creation + ValueLatch createResult; + i.setHandler(TEST_DIR, IN_CREATE, [&](const std::string& name, uint32_t) { + createResult.set(name); + }); + utils::createFile(FILE_PATH, O_WRONLY | O_CREAT, 0666); + BOOST_REQUIRE_EQUAL(createResult.get(), FILE_NAME); + + // Redefine the callback for delete + ValueLatch deleteResult; + i.setHandler(TEST_DIR, IN_DELETE, [&](const std::string& name, uint32_t) { + deleteResult.set(name); + }); + fs::remove(FILE_PATH); + BOOST_REQUIRE_EQUAL(deleteResult.get(), FILE_NAME); +} + +BOOST_AUTO_TEST_CASE(CreateDeleteDirHandler) +{ + ipc::epoll::ThreadDispatcher dispatcher; + Inotify i(dispatcher.getPoll()); + + // Callback on creation + ValueLatch createResult; + i.setHandler(TEST_DIR, IN_CREATE, [&](const std::string& name, uint32_t) { + createResult.set(name); + }); + utils::createEmptyDir(DIR_PATH); + BOOST_REQUIRE_EQUAL(createResult.get(), DIR_NAME); + + + // Redefine the callback for delete + ValueLatch deleteResult; + i.setHandler(TEST_DIR, IN_DELETE, [&](const std::string& name, uint32_t) { + deleteResult.set(name); + }); + fs::remove_all(DIR_PATH); + BOOST_REQUIRE_EQUAL(deleteResult.get(), DIR_NAME); +} + +BOOST_AUTO_TEST_CASE(NoFalseEventHandler) +{ + ipc::epoll::ThreadDispatcher dispatcher; + Inotify i(dispatcher.getPoll()); + + utils::createFile(FILE_PATH, O_WRONLY | O_CREAT, 0666); + + // Callback on creation shouldn't be called + ValueLatch createResult; + i.setHandler(TEST_DIR, IN_CREATE, [&](const std::string& name, uint32_t) { + createResult.set(name); + }); + fs::remove(FILE_PATH); + BOOST_REQUIRE_THROW(createResult.get(10), UtilsException); +} + +BOOST_AUTO_TEST_CASE(RemoveHandler) +{ + ipc::epoll::ThreadDispatcher dispatcher; + Inotify i(dispatcher.getPoll()); + + // Callback on creation + ValueLatch createResult; + i.setHandler(TEST_DIR, IN_CREATE, [&](const std::string& name, uint32_t) { + createResult.set(name); + }); + i.removeHandler(TEST_DIR); + utils::createFile(FILE_PATH, O_WRONLY | O_CREAT, 0666); + fs::remove(FILE_PATH); + BOOST_REQUIRE_THROW(createResult.get(10), UtilsException); +} + +BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From 5d612bd13106f445abeeebf310bd3dfc8d47e742 Mon Sep 17 00:00:00 2001 From: Krzysztof Dynowski Date: Mon, 12 Oct 2015 17:38:27 +0200 Subject: [PATCH 06/16] lxcpp: cgroups API implementation (part 1) [Feature] Control-groups API for containers [Cause] N/A [Solution] N/A [Verification] build, install, run unit tests Change-Id: I13e921b7568b9d2adf70c9499360d77daf80dee2 --- common/utils/fs.cpp | 2 +- common/utils/text.cpp | 31 ++++++ common/utils/text.hpp | 14 ++- libs/lxcpp/cgroups/cgroup.cpp | 72 +++++++++++++- libs/lxcpp/cgroups/cgroup.hpp | 23 +++-- libs/lxcpp/cgroups/subsystem.cpp | 171 ++++++++++++++++++++++++++++++++++ libs/lxcpp/cgroups/subsystem.hpp | 26 +++++- libs/lxcpp/exception.hpp | 5 + tests/unit_tests/lxcpp/ut-cgroups.cpp | 83 +++++++++++++++++ tests/unit_tests/lxcpp/ut-network.cpp | 1 - tests/unit_tests/utils/ut-text.cpp | 44 +++++++++ 11 files changed, 452 insertions(+), 20 deletions(-) create mode 100644 libs/lxcpp/cgroups/subsystem.cpp create mode 100644 tests/unit_tests/lxcpp/ut-cgroups.cpp create mode 100644 tests/unit_tests/utils/ut-text.cpp diff --git a/common/utils/fs.cpp b/common/utils/fs.cpp index 62e6c37..454ea4c 100644 --- a/common/utils/fs.cpp +++ b/common/utils/fs.cpp @@ -220,7 +220,7 @@ bool mount(const std::string& source, bool umount(const std::string& path) { if (::umount(path.c_str()) != 0) { - LOGD("Umount failed for '" << path << "': " << getSystemErrorMessage()); + LOGE("Umount failed for '" << path << "': " << getSystemErrorMessage()); return false; } return true; diff --git a/common/utils/text.cpp b/common/utils/text.cpp index 5bdf335..72ba65f 100644 --- a/common/utils/text.cpp +++ b/common/utils/text.cpp @@ -22,6 +22,7 @@ */ #include "utils/text.hpp" +#include namespace utils { namespace { @@ -40,4 +41,34 @@ std::string toHexString(const void *data, unsigned len) return s; } +std::string join(const std::vector& vec, const char *delim) +{ + std::stringstream res; + for (const auto& s : vec) { + if (res.tellp() > 0) { + res << delim; + } + res << s; + } + return res.str(); +} + +std::vector split(const std::string& str, const std::string& delim) +{ + std::vector tokens; + if (str.empty()) { + return tokens; + } + + for (std::string::size_type startPos = 0; ; ) { + std::string::size_type endPos = str.find_first_of(delim, startPos); + tokens.push_back(str.substr(startPos, endPos)); + if (endPos == std::string::npos) { + break; + } + startPos = endPos + 1; + } + return tokens; +} + } // namespace utils diff --git a/common/utils/text.hpp b/common/utils/text.hpp index 435f421..465f649 100644 --- a/common/utils/text.hpp +++ b/common/utils/text.hpp @@ -25,14 +25,10 @@ #define COMMON_UTILS_TEXT_HPP #include +#include namespace utils { -/** - * Convert binary bytes array to hex string representation - */ -std::string toHexString(const void *data, unsigned len); - inline bool beginsWith(std::string const &value, std::string const &part) { if (part.size() > value.size()) { @@ -49,6 +45,14 @@ inline bool endsWith(std::string const &value, std::string const &part) return std::equal(part.rbegin(), part.rend(), value.rbegin()); } +/** + * Convert binary bytes array to hex string representation + */ +std::string toHexString(const void *data, unsigned len); + +std::string join(const std::vector& vec, const char *delim); +std::vector split(const std::string& str, const std::string& delim); + } // namespace utils #endif // COMMON_UTILS_TEXT_HPP diff --git a/libs/lxcpp/cgroups/cgroup.cpp b/libs/lxcpp/cgroups/cgroup.cpp index 574af61..688058d 100644 --- a/libs/lxcpp/cgroups/cgroup.cpp +++ b/libs/lxcpp/cgroups/cgroup.cpp @@ -22,5 +22,75 @@ */ #include "lxcpp/cgroups/cgroup.hpp" +#include "lxcpp/exception.hpp" +#include "utils/fs.hpp" +#include "logger/logger.hpp" -// added this file now, to make hpp go through compilation +namespace fs = boost::filesystem; + +namespace lxcpp { + +namespace { +std::string getSubsysName(const std::string& s) { + auto p = s.find(':'); + if (p == std::string::npos) { + const std::string msg = "wgrong cgroup format"; + LOGE(msg); + throw CGroupException(msg); + } + return s.substr(0, p); +} +std::string getCGroupName(const std::string& s) { + auto p = s.find(':'); + if (p == std::string::npos) { + const std::string msg = "wgrong cgroup format"; + LOGE(msg); + throw CGroupException(msg); + } + return s.substr(p + 1); +} +} // namespace + +CGroup::CGroup(const std::string& subsysAndCgroup) : + mSubsys(std::move(getSubsysName(subsysAndCgroup))), + mName(std::move(getCGroupName(subsysAndCgroup))) +{ +} + +bool CGroup::exists() const +{ + const fs::path path = fs::path(mSubsys.getMountPoint()) / mName; + return fs::is_directory(path); +} + +void CGroup::create() +{ + const fs::path path = fs::path(mSubsys.getMountPoint()) / mName; + fs::create_directory(path); +} + +void CGroup::destroy() +{ + const fs::path path = fs::path(mSubsys.getMountPoint()) / mName; + fs::remove_all(path); +} + +void CGroup::setValue(const std::string& param, const std::string& value) +{ + const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / (mSubsys.getName() + "." + param); + utils::saveFileContent(path.string(), value); +} + +std::string CGroup::getValue(const std::string& param) const +{ + const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / (mSubsys.getName() + "." + param); + return utils::readFileContent(path.string()); +} + +void CGroup::assignProcess(pid_t pid) +{ + const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / "tasks"; + utils::saveFileContent(path.string(), std::to_string(pid)); +} + +} //namespace lxcpp diff --git a/libs/lxcpp/cgroups/cgroup.hpp b/libs/lxcpp/cgroups/cgroup.hpp index b47268f..f8d5698 100644 --- a/libs/lxcpp/cgroups/cgroup.hpp +++ b/libs/lxcpp/cgroups/cgroup.hpp @@ -26,23 +26,30 @@ #include "lxcpp/cgroups/subsystem.hpp" +namespace lxcpp { + class CGroup { public: /** * Define control-group object */ - CGroup(const Subsystem& subsys, const std::string& name) : + CGroup(const std::string& subsys, const std::string& name) : mSubsys(subsys), mName(name) { } /** + * Define control-group object (format "subsys:cgroup_path") + */ + CGroup(const std::string& subsysAndCgroup); + + /** * Check if cgroup exists * @return true if cgroup path (subsys.path / mName) exists */ - bool exists(); + bool exists() const; /** * Create cgroup directory @@ -67,17 +74,19 @@ public: * Get cgroup parameter * Equivalent of: cat mSubsys_path/mName/mSubsys_name.param */ - std::string getValue(const std::string& key); + std::string getValue(const std::string& param) const; /** - * Move process to this cgroup (process can't be removed from a cgroup) + * Assign process to this cgroup (will be removed from previous cgroup automatically) * Equivalent of: echo pid > mSubsys_path/mName/tasks */ - void moveProcess(pid_t pid); + void assignProcess(pid_t pid); private: - const Subsystem& mSubsys; // referred subsystem - const std::string& mName; // path relative to subsystem "root" + const Subsystem mSubsys; // referred subsystem + const std::string mName; // path relative to subsystem "root" }; +} //namespace lxcpp + #endif // LXCPP_CGROUPS_CGROUP_HPP diff --git a/libs/lxcpp/cgroups/subsystem.cpp b/libs/lxcpp/cgroups/subsystem.cpp new file mode 100644 index 0000000..dc18683 --- /dev/null +++ b/libs/lxcpp/cgroups/subsystem.cpp @@ -0,0 +1,171 @@ +/* + * 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 Krzysztof Dynowski (k.dynowski@samsumg.com) + * @brief Control-groups management + */ + +#include "lxcpp/cgroups/subsystem.hpp" +#include "lxcpp/exception.hpp" + +#include "utils/exception.hpp" +#include "utils/text.hpp" +#include "utils/fs.hpp" +#include "logger/logger.hpp" + +#include +#include +#include +#include +#include + +namespace lxcpp { + +Subsystem::Subsystem(const std::string& name) : mName(name) +{ + if (mName.empty()) { + const std::string msg = "CGroup name is empty"; + LOGE(msg); + throw CGroupException(msg); + } + + std::vector av = availableSubsystems(); + //find mount point for a name + std::ifstream fileStream("/proc/mounts"); + if (!fileStream.good()) { + const std::string msg = "Failed to open /proc/mounts"; + LOGE(msg); + throw CGroupException(msg); + } + + std::string line; + while (std::getline(fileStream, line).good()) { + std::istringstream iss(line); + auto it = std::istream_iterator(iss); + it++; //skip device name (fake for cgroup filesystem type) + std::string path = *it++; //mount point + if (it->compare("cgroup") != 0) { //filesystem type + continue; + } + it++; //skip filesystem type + if (it->find(mName) != std::string::npos) { + mPath = std::move(path); + break; + } + } +} + +bool Subsystem::isAvailable() const +{ + if (mName.empty()) { + const std::string msg = "CGroup name is empty"; + LOGE(msg); + throw CGroupException(msg); + } + std::vector av = availableSubsystems(); + return std::find(av.begin(), av.end(), mName) != av.end(); +} + +bool Subsystem::isAttached() const +{ + return !mPath.empty(); +} + +const std::string& Subsystem::getMountPoint() const +{ + if (!isAttached()) { + const std::string msg = "CGroup '" + mName + "' is not attached"; + LOGE(msg); + throw CGroupException(msg); + } + return mPath; +} + +void Subsystem::attach(const std::string& path, const std::vector& subs) +{ + if (path.empty()) { + const std::string msg = "Trying attach to emtpy path"; + LOGE(msg); + throw CGroupException(msg); + } + if (!utils::createDirs(path,0777)) { + throw CGroupException("Can't create mount point: " + path + ", " + utils::getSystemErrorMessage()); + } + if (!utils::mount("cgroup", path, "cgroup", 0, utils::join(subs,","))) { + throw CGroupException("Can't mount cgroup: " + path + ", " + utils::getSystemErrorMessage()); + } +} + +void Subsystem::detach(const std::string& path) +{ + if (!utils::umount(path)) { + throw CGroupException("Can't umount cgroup: " + path + ", " + utils::getSystemErrorMessage()); + } +} + +std::vector Subsystem::availableSubsystems() +{ + std::ifstream fileStream("/proc/cgroups"); + if (!fileStream.good()) { + const std::string msg = "Failed to open /proc/cgroups"; + LOGE(msg); + throw CGroupException(msg); + } + + std::vector subs; + std::string line; + while (std::getline(fileStream, line).good()) { + if (utils::beginsWith(line, "#")) { + continue; + } + std::istringstream iss(line); + auto it = std::istream_iterator(iss); + std::string n = *it++; //subsystem name + subs.push_back(n); + } + return subs; +} + +std::vector Subsystem::getCGroups(pid_t pid) +{ + std::ifstream fileStream("/proc/" + std::to_string(pid) + "/cgroup"); + if (!fileStream.good()) { + const std::string msg = "Failed to open /proc//cgroup"; + LOGE(msg); + throw CGroupException(msg); + } + + std::vector subs; + std::string line; + while (std::getline(fileStream, line).good()) { + if (utils::beginsWith(line, "#")) { + continue; + } + // istream_iterator does not support delimiter + std::istringstream iss(line); + std::string n, p; + std::getline(iss, n, ':'); // ignore + std::getline(iss, n, ':'); // subsystem name + std::getline(iss, p, ':'); // cgroup path + subs.push_back(n + ":" + p); + } + return subs; +} + +} //namespace lxcpp diff --git a/libs/lxcpp/cgroups/subsystem.hpp b/libs/lxcpp/cgroups/subsystem.hpp index bb9887e..a4b7c75 100644 --- a/libs/lxcpp/cgroups/subsystem.hpp +++ b/libs/lxcpp/cgroups/subsystem.hpp @@ -29,6 +29,8 @@ #include #include +namespace lxcpp { + class Subsystem { public: /** @@ -36,23 +38,35 @@ public: */ Subsystem(const std::string& name); + const std::string& getName() const + { + return mName; + } + /** * Check if named subsystem is supported by the kernel * @return true if subsystem is listed in /proc/cgroups */ - bool isAvailable(); + bool isAvailable() const; /** * Check if named subsystem is mounted (added to hierarchy) * @return true if subsystem has a mount point (as read from /proc/mounts) */ - bool isAttached(); + bool isAttached() const; + + /** + * Get mount point of this subsystem + * @return subsystem mount point (as read from /proc/mounts) + */ + const std::string& getMountPoint() const; /** * Attach subsystem hierarchy to filesystem - * Equivalent of: mount -t cgroup -o subs(coma-sep) subs(underln-sep) path + * Equivalent of: mount -t cgroup -o subs(coma-sep) cgroup path + * Note: cgroup root must be already mounted (eg. /sys/fs/cgroup) as tmpfs */ - static void attach(const std::string& path, std::vector subs); + static void attach(const std::string& path, const std::vector& subs); /** * Detach subsstem hierarchy from filesystem @@ -74,8 +88,10 @@ public: static std::vector getCGroups(pid_t pid); private: - const std::string& mName; + std::string mName; std::string mPath; }; +} //namespace lxcpp + #endif // LXCPP_CGROUPS_SUBSYSTEM_HPP diff --git a/libs/lxcpp/exception.hpp b/libs/lxcpp/exception.hpp index 37fec5a..061bc6c 100644 --- a/libs/lxcpp/exception.hpp +++ b/libs/lxcpp/exception.hpp @@ -91,6 +91,11 @@ struct NetworkException : public Exception { : Exception(message) {} }; +struct CGroupException : public Exception { + explicit CGroupException (const std::string& message = "Error during setting up a cgroup") + : Exception(message) {} +}; + struct ConfigureException: public Exception { explicit ConfigureException(const std::string& message = "Error while configuring a container") : Exception(message) {} diff --git a/tests/unit_tests/lxcpp/ut-cgroups.cpp b/tests/unit_tests/lxcpp/ut-cgroups.cpp new file mode 100644 index 0000000..510aba3 --- /dev/null +++ b/tests/unit_tests/lxcpp/ut-cgroups.cpp @@ -0,0 +1,83 @@ +/* + * 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 Krzysztof Dynowski (k.dynowski@samsung.com) + * @brief Unit tests of lxcpp cgroups managment + */ + +#include "config.hpp" +#include "ut.hpp" +#include "logger/logger.hpp" + +#include "lxcpp/cgroups/subsystem.hpp" + +namespace { + +struct Fixture { + Fixture() {} + ~Fixture() {} +}; + +} // namespace + +BOOST_FIXTURE_TEST_SUITE(LxcppCGroupsSuite, Fixture) + +using namespace lxcpp; + +// assume cgroups are supprted by the system +BOOST_AUTO_TEST_CASE(GetAvailable) +{ + std::vector subs; + BOOST_CHECK_NO_THROW(subs = Subsystem::availableSubsystems()); + BOOST_CHECK(subs.size() > 0); + for (auto n : subs){ + Subsystem s(n); + LOGD(s.getName() << ": " << (s.isAttached()?s.getMountPoint():"[not attached]")); + } +} + +BOOST_AUTO_TEST_CASE(GetCGroupsByPid) +{ + std::vector cg; + BOOST_CHECK_NO_THROW(cg=Subsystem::getCGroups(::getpid())); + BOOST_CHECK(cg.size() > 0); +} + +BOOST_AUTO_TEST_CASE(SubsysAttach) +{ + Subsystem sub("freezer"); + BOOST_CHECK_MESSAGE(sub.getName() == "freezer", "freezer not equal"); + BOOST_CHECK_MESSAGE(sub.isAvailable(), "freezer not found"); + + if (!sub.isAvailable()) return ; + + + if (sub.isAttached()) { + std::string mp = sub.getMountPoint(); + BOOST_CHECK_NO_THROW(Subsystem::detach(mp)); + BOOST_CHECK_NO_THROW(Subsystem::attach(mp, {sub.getName()})); + } + else { + std::string mp = "/sys/fs/cgroup/" + sub.getName(); + BOOST_CHECK_NO_THROW(Subsystem::attach(mp, {sub.getName()})); + BOOST_CHECK_NO_THROW(Subsystem::detach(mp)); + } +} + +BOOST_AUTO_TEST_SUITE_END() diff --git a/tests/unit_tests/lxcpp/ut-network.cpp b/tests/unit_tests/lxcpp/ut-network.cpp index a4741f6..75b94c1 100644 --- a/tests/unit_tests/lxcpp/ut-network.cpp +++ b/tests/unit_tests/lxcpp/ut-network.cpp @@ -30,7 +30,6 @@ #include "ut.hpp" #include -#include #include diff --git a/tests/unit_tests/utils/ut-text.cpp b/tests/unit_tests/utils/ut-text.cpp new file mode 100644 index 0000000..b7d8a6d --- /dev/null +++ b/tests/unit_tests/utils/ut-text.cpp @@ -0,0 +1,44 @@ +/* + * 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 Krzysztof Dynowski (k.dynowski@samsung.com) + * @brief Unit tests of text helpers + */ + +#include "config.hpp" +#include "ut.hpp" + +#include "utils/text.hpp" + +BOOST_AUTO_TEST_SUITE(TextUtilsSuite) + +BOOST_AUTO_TEST_CASE(SplitText) +{ + std::vector v; + v = utils::split("", ","); + BOOST_CHECK(v.size() == 0); + v = utils::split("a", ","); + BOOST_CHECK(v.size() == 1); + v = utils::split(",", ","); + BOOST_CHECK(v.size() == 2); + v = utils::split("1,2", ","); + BOOST_CHECK(v.size() == 2); +} + +BOOST_AUTO_TEST_SUITE_END() -- 2.7.4 From b56df400cad1492b17c896615dc0516d6825decf Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Wed, 21 Oct 2015 18:32:34 +0200 Subject: [PATCH 07/16] Use enum class in logger-config as it is possible to serialize now. [Bug/Feature] N/A [Cause] To keep things clean and consistent [Solution] N/A [Verification] Build, run the junk tester Change-Id: I75e55448a5f7c559882c6433dc82fae60ab2083b --- libs/lxcpp/guard/guard.cpp | 6 +++--- libs/lxcpp/logger-config.cpp | 4 ++-- libs/lxcpp/logger-config.hpp | 13 ++++--------- 3 files changed, 9 insertions(+), 14 deletions(-) diff --git a/libs/lxcpp/guard/guard.cpp b/libs/lxcpp/guard/guard.cpp index f96fe7a..bc5f112 100644 --- a/libs/lxcpp/guard/guard.cpp +++ b/libs/lxcpp/guard/guard.cpp @@ -63,9 +63,9 @@ Guard::Guard(const int channelFD) mChannel.setCloseOnExec(true); config::loadFromFD(mChannel.getFD(), mConfig); - logger::setupLogger(mConfig.mLogger.getType(), - mConfig.mLogger.getLevel(), - mConfig.mLogger.getArg()); + logger::setupLogger(mConfig.mLogger.mType, + mConfig.mLogger.mLevel, + mConfig.mLogger.mArg); LOGD("Config & logging restored"); diff --git a/libs/lxcpp/logger-config.cpp b/libs/lxcpp/logger-config.cpp index 3aed302..ff0e407 100644 --- a/libs/lxcpp/logger-config.cpp +++ b/libs/lxcpp/logger-config.cpp @@ -39,8 +39,8 @@ void LoggerConfig::set(const logger::LogType type, } } - mType = static_cast(type); - mLevel = static_cast(level); + mType = type; + mLevel = level; mArg = arg; } diff --git a/libs/lxcpp/logger-config.hpp b/libs/lxcpp/logger-config.hpp index 8312623..52f0514 100644 --- a/libs/lxcpp/logger-config.hpp +++ b/libs/lxcpp/logger-config.hpp @@ -35,21 +35,16 @@ namespace lxcpp { /** * Logger configuration */ -struct LoggerConfig { -private: - int mType; - int mLevel; +struct LoggerConfig +{ + logger::LogType mType; + logger::LogLevel 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, -- 2.7.4 From 54970c54480e58c5f69d4dd42f0bb161681b0e00 Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Thu, 22 Oct 2015 15:50:14 +0200 Subject: [PATCH 08/16] Add link to demo movie. [Bug/Feature] Add link to demo movie [Cause] N/A [Solution] N/A [Verification] N/A Change-Id: I68e14dc5b80819170c4a000694c31b405d689d2b --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5428a92..0d3852a 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,9 @@ For now Vasum uses [LXC](https://linuxcontainers.org/lxc/introduction/) for Linu Vasum's development takes place on [review.tizen.org/gerrit/](http://review.tizen.org/gerrit/) (registration on [tizen.org](http://tizen.org) is required). +## Vasum demo @youtube +[![IMAGE ALT TEXT](http://img.youtube.com/vi/hsNvI9kHTvI/0.jpg)](http://www.youtube.com/watch?v=hsNvI9kHTvI "Vasum demo - Fedora 22 Desktop running in Linux container ") + ## Installation and usage The installation process and simple verification is described [here](https://wiki.tizen.org/wiki/Security:Vasum:Usage). @@ -63,4 +66,5 @@ You can find the options file in the root of the project. For example to format all .cpp and .hpp files run in the project directory: - astyle --options=./astylerc --recursive ./*.cpp ./*.hpp \ No newline at end of file + astyle --options=./astylerc --recursive ./*.cpp ./*.hpp + -- 2.7.4 From 300d71d7108291c07a89ee122c2143ea55b6d3a1 Mon Sep 17 00:00:00 2001 From: "Maciej J. Karpiuk" Date: Mon, 19 Oct 2015 14:03:14 +0200 Subject: [PATCH 09/16] lxcpp: provisioning implementation (part 2) [Feature] Provisioning implementation for lxcpp: commands. [Cause] N/A [Solution] N/A [Verification] Build, install, run tests Change-Id: I3089059c5c4491553a4f45876f372ccb6daab3bb --- common/utils/fs.cpp | 9 +++++ common/utils/fs.hpp | 5 +++ libs/lxcpp/commands/provision.cpp | 83 ++++++++++++++++++++++++++++++++++++--- libs/lxcpp/commands/provision.hpp | 15 ++----- 4 files changed, 94 insertions(+), 18 deletions(-) diff --git a/common/utils/fs.cpp b/common/utils/fs.cpp index 454ea4c..bae21f5 100644 --- a/common/utils/fs.cpp +++ b/common/utils/fs.cpp @@ -163,6 +163,15 @@ void assertIsDir(const std::string& path) } } +void assertIsAbsolute(const std::string& path) +{ + if (!fs::path(path).is_absolute()) { + const std::string msg = "Given path '" + path + "' must be absolute!"; + LOGE(msg); + throw UtilsException(msg); + } +} + namespace { // NOTE: Should be the same as in systemd/src/core/mount-setup.c diff --git a/common/utils/fs.hpp b/common/utils/fs.hpp index 2237450..2b95073 100644 --- a/common/utils/fs.hpp +++ b/common/utils/fs.hpp @@ -70,6 +70,11 @@ bool isCharDevice(const std::string& path); void assertIsDir(const std::string& path); /** + * Checks if path is absolute + */ +void assertIsAbsolute(const std::string& path); + +/** * List all (including '.' and '..' entries) dir entries */ bool listDir(const std::string& path, std::vector& files); diff --git a/libs/lxcpp/commands/provision.cpp b/libs/lxcpp/commands/provision.cpp index ba97393..d03d8c8 100644 --- a/libs/lxcpp/commands/provision.cpp +++ b/libs/lxcpp/commands/provision.cpp @@ -24,9 +24,17 @@ #include "lxcpp/commands/provision.hpp" #include "lxcpp/container.hpp" #include "lxcpp/provision-config.hpp" +#include "lxcpp/filesystem.hpp" +#include "utils/fs.hpp" +#include +#include + +// TODO: Cleanup file/path handling namespace lxcpp { +namespace fs = boost::filesystem; + void Provisions::execute() { for(const auto & file : mConfig.mProvisions.files) { @@ -56,34 +64,97 @@ void Provisions::revert() } } +ProvisionFile::ProvisionFile(ContainerConfig &config, const provision::File &file) + : mConfig(config), mFile(file) +{ + utils::assertIsAbsolute(file.path); +} void ProvisionFile::execute() { - // MJK TODO: add file + using namespace provision; + const fs::path hostPath = fs::path(mConfig.mRootPath) / fs::path(mFile.path); + + switch (mFile.type) { + case File::Type::DIRECTORY: + if (!utils::createDirs(hostPath.string(), mFile.mode)) { + const std::string msg = "Can't create dir: " + hostPath.string(); + LOGE(msg); + throw ProvisionException(msg); + } + break; + + case File::Type::FIFO: + if (!utils::createFifo(hostPath.string(), mFile.mode)) { + const std::string msg = "Failed to make fifo: " + mFile.path; + LOGE(msg); + throw ProvisionException(msg); + } + break; + + case File::Type::REGULAR: + if ((mFile.flags & O_CREAT)) { + if (!utils::createFile(hostPath.string(), mFile.flags, mFile.mode)) { + const std::string msg = "Failed to create file: " + mFile.path; + LOGE(msg); + throw ProvisionException(msg); + } + } else { + if (!utils::copyFile(mFile.path, hostPath.string())) { + const std::string msg = "Failed to copy file: " + mFile.path; + LOGE(msg); + throw ProvisionException(msg); + } + } + break; + } } void ProvisionFile::revert() { - // MJK TODO: remove file from container + // TODO decision: should remove the file? } +ProvisionMount::ProvisionMount(ContainerConfig &config, const provision::Mount &mount) + : mConfig(config), mMount(mount) +{ + utils::assertIsAbsolute(mount.target); +} + void ProvisionMount::execute() { - // MJK TODO: add mount + const fs::path hostPath = fs::path(mConfig.mRootPath) / fs::path(mMount.target); + + lxcpp::mount(mMount.source, hostPath.string(), mMount.type, mMount.flags, mMount.data); } void ProvisionMount::revert() { - // MJK TODO: remove mount from container + const fs::path hostPath = fs::path(mConfig.mRootPath) / fs::path(mMount.target); + + lxcpp::umount(hostPath.string(), MNT_DETACH); } +ProvisionLink::ProvisionLink(ContainerConfig &config, const provision::Link &link) + : mConfig(config), mLink(link) +{ + utils::assertIsAbsolute(link.target); +} + void ProvisionLink::execute() { - // MJK TODO: add link + const std::string srcHostPath = fs::path(mLink.source).normalize().string(); + const fs::path destHostPath = fs::path(mConfig.mRootPath) / fs::path(mLink.target); + + if (!utils::createLink(srcHostPath, destHostPath.string())) { + const std::string msg = "Failed to create hard link: " + mLink.source; + LOGE(msg); + throw ProvisionException(msg); + } } void ProvisionLink::revert() { - // MJK TODO: remove link from container + // TODO decision: should remove the link? } } // namespace lxcpp diff --git a/libs/lxcpp/commands/provision.hpp b/libs/lxcpp/commands/provision.hpp index 0b7411a..350e967 100644 --- a/libs/lxcpp/commands/provision.hpp +++ b/libs/lxcpp/commands/provision.hpp @@ -58,10 +58,7 @@ public: * * Add/remove new file/fifo/dir provision to/from the container */ - ProvisionFile(ContainerConfig &config, const provision::File &file) : - mConfig(config), mFile(file) - { - } + ProvisionFile(ContainerConfig &config, const provision::File &file); void execute(); void revert(); @@ -78,10 +75,7 @@ public: * * Add/remove new mount provision to/from the container */ - ProvisionMount(ContainerConfig &config, const provision::Mount &mount) : - mConfig(config), mMount(mount) - { - } + ProvisionMount(ContainerConfig &config, const provision::Mount &mount); void execute(); void revert(); @@ -98,10 +92,7 @@ public: * * Add/remove link provision to/from the container */ - ProvisionLink(ContainerConfig &config, const provision::Link &link) : - mConfig(config), mLink(link) - { - } + ProvisionLink(ContainerConfig &config, const provision::Link &link); void execute(); void revert(); -- 2.7.4 From cb6c850ba9cce8c714c64e02b43fb8d5480b8c8b Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Fri, 23 Oct 2015 14:10:41 +0200 Subject: [PATCH 10/16] Minor documentation fixes. [Feature] Minor documentation fixes. [Cause] N/A [Solution] N/A [Verification] Generate documentation. Change-Id: Id14ffc07725296aa2690b6afce24e95ab3bc45d9 --- doc/mainpage.md | 3 ++ libs/ipc/internals/processor.hpp | 3 ++ libs/lxcpp/network.hpp | 100 ++++++++++++++++++++------------------- 3 files changed, 57 insertions(+), 49 deletions(-) diff --git a/doc/mainpage.md b/doc/mainpage.md index 74635db..35e347c 100644 --- a/doc/mainpage.md +++ b/doc/mainpage.md @@ -8,6 +8,9 @@ For now Vasum uses [LXC](https://linuxcontainers.org/lxc/introduction/) for Linu Vasum's development takes place on [review.tizen.org/gerrit/](http://review.tizen.org/gerrit/) (registration on [tizen.org](http://tizen.org) is required). +## Vasum demo +Fedora 22 Desktop running in Linux container on [youtube](http://www.youtube.com/watch?v=hsNvI9kHTvI) + ## Installation and usage The installation process and simple verification is described [here](https://wiki.tizen.org/wiki/Security:Vasum:Usage "Vasum on Tizen"). diff --git a/libs/ipc/internals/processor.hpp b/libs/ipc/internals/processor.hpp index 91edfc1..c032269 100644 --- a/libs/ipc/internals/processor.hpp +++ b/libs/ipc/internals/processor.hpp @@ -117,8 +117,11 @@ public: * Constructs the Processor, but doesn't start it. * The object is ready to add methods. * + * @param eventPoll event poll + * @param logName log name * @param newPeerCallback called when a new peer arrives * @param removedPeerCallback called when the Processor stops listening for this peer + * @param maxNumberOfPeers maximal number of peers */ Processor(epoll::EventPoll& eventPoll, const std::string& logName = "", diff --git a/libs/lxcpp/network.hpp b/libs/lxcpp/network.hpp index ac94c44..eeb5897 100644 --- a/libs/lxcpp/network.hpp +++ b/libs/lxcpp/network.hpp @@ -218,7 +218,7 @@ class NetworkInterface { //TODO implement Netlink singleton per pid public: /** - * Create network interface object for the ifname in the container (network namespace) + * Create network interface object for the @b ifname in the container (network namespace) */ NetworkInterface(const std::string& ifname, pid_t pid = 0) : mIfname(ifname), @@ -234,137 +234,139 @@ public: NetStatus status() const; /** - * Create network interface in container identified by @mContainerPid + * Create network interface in container identified by @ref mContainerPid. * - * Equivalent to: ip link add @mIfname type @type [...] - * Create pair of virtual ethernet interfaces - * ip link add @mIfname type veth peer name @peerif - * Create bridge interface - * ip link add @mIfname type bridge - * Create psedo-ethernet interface on existing one - * ip link add @mIfname type macvlan link @peerif [mode @a mode] + * Equivalent to: ip link add @ref mIfname type @b type [...] + * + * Create pair of virtual ethernet interfaces: + * - ip link add @ref mIfname type veth peer name @b peerif + * + * Create bridge interface: + * - ip link add @ref mIfname type bridge + * + * Create pseudo-ethernet interface on existing one: + * - ip link add @ref mIfname type macvlan link @b peerif [mode @b mode] */ void create(InterfaceType type, const std::string& peerif = "", MacVLanMode mode = MacVLanMode::PRIVATE); /** - * Delete interface - * Equivalent to: ip link delete @mIfname + * Delete interface. + * Equivalent to: ip link delete @ref mIfname */ void destroy(); /** - * Move interface to container - * Equivalent to: ip link set dev @mIfname netns @pid + * Move interface to container. + * Equivalent to: ip link set dev @ref mIfname netns @b pid */ void moveToContainer(pid_t pid); /** - * Rename interface name - * Equivalent to: ip link set dev @oldif name @mIfname + * Rename interface name. + * Equivalent to: ip link set dev @b oldif name @ref mIfname */ void renameFrom(const std::string& oldif); /** - * Add interface to the bridge - * Equivalent to: ip link set @mIfname master @bridge + * Add interface to the bridge. + * Equivalent to: ip link set @ref mIfname master @b bridge */ void addToBridge(const std::string& bridge); /** - * Remove insterface from the bridge - * Equivalent to: ip link set @mIfname nomaster + * Remove insterface from the bridge. + * Equivalent to: ip link set @ref mIfname nomaster */ void delFromBridge(); /** * Set or get interface attributes in one netlink call. - * Supported attributes: see @AttrNames + * Supported attributes: see @ref AttrName */ void setAttrs(const Attrs& attrs); Attrs getAttrs() const; /** - * Add inet address to the interface - * Equivalent to: ip addr add @addr dev @mIfname + * Add inet address to the interface. + * Equivalent to: ip addr add @b addr dev @ref mIfname */ void addInetAddr(const InetAddr& addr); /** - * Remove inet address from the interface - * Equivalent to: ip addr del @addr dev @mIfname + * Remove inet address from the interface. + * Equivalent to: ip addr del @b addr dev @ref mIfname */ void delInetAddr(const InetAddr& addr); /** - * Retrieve all inet addresses for the interface + * Retrieve all inet addresses for the interface. * Equivalent to: ip addr show, ip -6 addr show */ std::vector getInetAddressList() const; /** - * Add route to specified routing table - * Equivalent to: ip route add @route.dst.addr/@route.dst.prefix dev @mIfname (if route.src.prefix=0) + * Add route to specified routing table. + * Equivalent to: ip route add @b route.dst.addr/@b route.dst.prefix dev @ref mIfname (if route.src.prefix=0) */ void addRoute(const Route& route, const RoutingTable rt = RoutingTable::MAIN); /** - * Remove route from specified routing table - * Equivalent to: ip route del @route.dst.addr dev @mIfname + * Remove route from specified routing table. + * Equivalent to: ip route del @b route.dst.addr dev @ref mIfname */ void delRoute(const Route& route, const RoutingTable rt = RoutingTable::MAIN); /** - * Retrieve routing table for the interface - * Equivalent to: ip route show dev @mIfname table @rt + * Retrieve routing table for the interface. + * Equivalent to: ip route show dev @ref mIfname table @b rt */ std::vector getRoutes(const RoutingTable rt = RoutingTable::MAIN) const; /** - * Set interface up - * Equivalent to: ip link set @mIfname up + * Set interface up. + * Equivalent to: ip link set @ref mIfname up */ void up(); /** - * Set interface down - * Equivalent to: ip link set @mInface down + * Set interface down. + * Equivalent to: ip link set @ref mIfname down */ void down(); /** - * Set MAC address attribute - * Equivalent to: ip link set @mIfname address @macaddr - * @macaddr in format AA:BB:CC:DD:FF:GG + * Set MAC address attribute. + * Equivalent to: ip link set @ref mIfname address @b macaddr (@b macaddr in format AA:BB:CC:DD:FF:GG) * * Note: two lower bits of first byte (leftmost) specifies MAC address class: - * b1: 0=unicast, 1=broadcast - * b2: 0=global, 1=local - * in most cases should be b2=0, b1=1 - * (see: https://en.wikipedia.org/wiki/MAC_address) + * - b1: 0=unicast, 1=broadcast + * - b2: 0=global, 1=local + * + * In most cases should be b2=0, b1=1, (see: https://en.wikipedia.org/wiki/MAC_address) */ void setMACAddress(const std::string& macaddr); /** - * Set MTU attribute - * Equivalent to: ip link set @mIfname mtu @mtu + * Set MTU attribute. + * Equivalent to: ip link set @ref mIfname mtu @b mtu */ void setMTU(int mtu); /** - * Set TxQ attribute - * Equivalent to: ip link set @mIfname txqueue @txlen + * Set TxQ attribute. + * Equivalent to: ip link set @ref mIfname txqueue @b txlen */ void setTxLength(int txlen); /** - * Get list of network interafece names + * Get list of network interafece names. * Equivalent to: ip link show */ static std::vector getInterfaces(pid_t initpid); /** - * Get list of routes (specified routing table) - * Equivalent to: ip route show table @rt + * Get list of routes (specified routing table). + * Equivalent to: ip route show table @b rt */ static std::vector getRoutes(pid_t initpid, const RoutingTable rt = RoutingTable::MAIN); -- 2.7.4 From ce3144640035f592ae41ae1905290b4d35a1d52d Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Mon, 26 Oct 2015 14:36:00 +0100 Subject: [PATCH 11/16] FIX: Don't switch to hostVT during testing. [Feature] FIX: Don't switch to hostVT during testing [Cause] N/A [Solution] N/A [Verification] Build, run tests. Change-Id: Ic02c2387b15a5a162e88806c2dcc5ec2c82e67b0 --- server/zones-manager.cpp | 6 ++++-- tests/unit_tests/configs/test-daemon.conf.in | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/server/zones-manager.cpp b/server/zones-manager.cpp index 7a2bf11..82c5e68 100644 --- a/server/zones-manager.cpp +++ b/server/zones-manager.cpp @@ -392,8 +392,10 @@ void ZonesManager::focusInternal(Zones::iterator iter) // assume mutex is locked if (iter == mZones.end()) { if (!mActiveZoneId.empty()) { - LOGI("Focus to: host"); - utils::activateVT(mConfig.hostVT); + if (mConfig.hostVT > 0) { + LOGI("Focus to: host"); + utils::activateVT(mConfig.hostVT); + } mActiveZoneId.clear(); } return; diff --git a/tests/unit_tests/configs/test-daemon.conf.in b/tests/unit_tests/configs/test-daemon.conf.in index 2ed411b..247bf1f 100644 --- a/tests/unit_tests/configs/test-daemon.conf.in +++ b/tests/unit_tests/configs/test-daemon.conf.in @@ -7,7 +7,7 @@ "zoneTemplateDir" : "@VSM_TEST_CONFIG_INSTALL_DIR@/templates/", "runMountPointPrefix" : "", "defaultId" : "", - "hostVT" : 2, + "hostVT" : -1, "availableVTs" : [], "inputConfig" : {"enabled" : false, "device" : "gpio-keys.4", -- 2.7.4 From af1459d7e79528ee0a87ff9a1f906ae40a7b297c Mon Sep 17 00:00:00 2001 From: Krzysztof Dynowski Date: Mon, 12 Oct 2015 17:38:27 +0200 Subject: [PATCH 12/16] lxcpp: cgroups API implementation (part 2) [Feature] Control-groups API for containers [Cause] N/A [Solution] N/A [Verification] build, install, run unit tests Change-Id: Ica81fcc9b9f31118dfe6167a6b55f814c6ec0453 --- common/utils/fs.cpp | 5 ++ common/utils/fs.hpp | 7 ++- common/utils/text.cpp | 13 ----- common/utils/text.hpp | 15 +++++- libs/lxcpp/cgroups/cgroup.cpp | 81 ++++++++++++++++++++++++++--- libs/lxcpp/cgroups/cgroup.hpp | 33 +++++++++++- libs/lxcpp/cgroups/devices.cpp | 95 +++++++++++++++++++++++++++++++++++ libs/lxcpp/cgroups/devices.hpp | 53 +++++++++++++++++++ libs/lxcpp/cgroups/subsystem.cpp | 1 - tests/unit_tests/lxcpp/ut-cgroups.cpp | 54 ++++++++++++++++++-- 10 files changed, 326 insertions(+), 31 deletions(-) create mode 100644 libs/lxcpp/cgroups/devices.cpp create mode 100644 libs/lxcpp/cgroups/devices.hpp diff --git a/common/utils/fs.cpp b/common/utils/fs.cpp index bae21f5..cd70e3b 100644 --- a/common/utils/fs.cpp +++ b/common/utils/fs.cpp @@ -47,6 +47,11 @@ namespace fs = boost::filesystem; namespace utils { +std::string readFileStream(const std::string& path) +{ + std::ifstream is(path); + return std::string(std::istreambuf_iterator(is), std::istreambuf_iterator()); +} std::string readFileContent(const std::string& path) { diff --git a/common/utils/fs.hpp b/common/utils/fs.hpp index 2b95073..e533670 100644 --- a/common/utils/fs.hpp +++ b/common/utils/fs.hpp @@ -34,7 +34,12 @@ namespace utils { /** - * Reads the content of a file; Throws exception on error + * Reads the content of file stream (no seek); Throws exception on error + */ +std::string readFileStream(const std::string& path); + +/** + * Reads the content of a file (performs seek); Throws exception on error */ std::string readFileContent(const std::string& path); diff --git a/common/utils/text.cpp b/common/utils/text.cpp index 72ba65f..eebc8f4 100644 --- a/common/utils/text.cpp +++ b/common/utils/text.cpp @@ -22,7 +22,6 @@ */ #include "utils/text.hpp" -#include namespace utils { namespace { @@ -41,18 +40,6 @@ std::string toHexString(const void *data, unsigned len) return s; } -std::string join(const std::vector& vec, const char *delim) -{ - std::stringstream res; - for (const auto& s : vec) { - if (res.tellp() > 0) { - res << delim; - } - res << s; - } - return res.str(); -} - std::vector split(const std::string& str, const std::string& delim) { std::vector tokens; diff --git a/common/utils/text.hpp b/common/utils/text.hpp index 465f649..5920b9f 100644 --- a/common/utils/text.hpp +++ b/common/utils/text.hpp @@ -26,6 +26,7 @@ #include #include +#include namespace utils { @@ -50,7 +51,19 @@ inline bool endsWith(std::string const &value, std::string const &part) */ std::string toHexString(const void *data, unsigned len); -std::string join(const std::vector& vec, const char *delim); +template +std::string join(const std::vector& vec, const char *delim) +{ + std::stringstream res; + for (const auto& s : vec) { + if (res.tellp()>0) { + res << delim; + } + res << s; + } + return res.str(); +} + std::vector split(const std::string& str, const std::string& delim); } // namespace utils diff --git a/libs/lxcpp/cgroups/cgroup.cpp b/libs/lxcpp/cgroups/cgroup.cpp index 688058d..5e72d21 100644 --- a/libs/lxcpp/cgroups/cgroup.cpp +++ b/libs/lxcpp/cgroups/cgroup.cpp @@ -24,6 +24,7 @@ #include "lxcpp/cgroups/cgroup.hpp" #include "lxcpp/exception.hpp" #include "utils/fs.hpp" +#include "utils/text.hpp" #include "logger/logger.hpp" namespace fs = boost::filesystem; @@ -31,24 +32,28 @@ namespace fs = boost::filesystem; namespace lxcpp { namespace { -std::string getSubsysName(const std::string& s) { +std::string getSubsysName(const std::string& s) +{ auto p = s.find(':'); if (p == std::string::npos) { - const std::string msg = "wgrong cgroup format"; + const std::string msg = "wrong subsys format " + s; LOGE(msg); throw CGroupException(msg); } return s.substr(0, p); } -std::string getCGroupName(const std::string& s) { + +std::string getCGroupName(const std::string& s) +{ auto p = s.find(':'); if (p == std::string::npos) { - const std::string msg = "wgrong cgroup format"; + const std::string msg = "wrong cgroup format " + s; LOGE(msg); throw CGroupException(msg); } return s.substr(p + 1); } + } // namespace CGroup::CGroup(const std::string& subsysAndCgroup) : @@ -72,25 +77,85 @@ void CGroup::create() void CGroup::destroy() { const fs::path path = fs::path(mSubsys.getMountPoint()) / mName; - fs::remove_all(path); + //remove_all is not good for cgroup filesystem + fs::remove(path); +} + +void CGroup::setCommonValue(const std::string& param, const std::string& value) +{ + const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / ("cgroup." + param); + if (!utils::saveFileContent(path.string(), value)) { + const std::string msg = "Invalid param " + param; + LOGE(msg); + throw CGroupException(msg); + } +} + +std::string CGroup::getCommonValue(const std::string& param) const +{ + const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / ("cgroup." + param); + return utils::readFileStream(path.string()); } void CGroup::setValue(const std::string& param, const std::string& value) { const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / (mSubsys.getName() + "." + param); - utils::saveFileContent(path.string(), value); + if (!utils::saveFileContent(path.string(), value)) { + const std::string msg = "Invalid param " + param; + LOGE(msg); + throw CGroupException(msg); + } } std::string CGroup::getValue(const std::string& param) const { const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / (mSubsys.getName() + "." + param); - return utils::readFileContent(path.string()); + return utils::readFileStream(path.string()); +} + +void CGroup::assignGroup(pid_t pid) +{ + setCommonValue("procs", std::to_string(pid)); } -void CGroup::assignProcess(pid_t pid) +void CGroup::assignPid(pid_t pid) { const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / "tasks"; utils::saveFileContent(path.string(), std::to_string(pid)); } +std::vector CGroup::getPids() const +{ + const fs::path path = fs::path(mSubsys.getMountPoint()) / mName / "tasks"; + std::ifstream fileStream(path.string()); + if (!fileStream.good()) { + const std::string msg = "Failed to open " + path.string(); + LOGE(msg); + throw CGroupException(msg); + } + + std::vector pids; + while (fileStream.good()) { + int pid; + fileStream >> pid; + pids.push_back(pid); + } + + return pids; +} + +CGroup CGroup::getCGroup(const std::string& subsys, pid_t pid) +{ + std::vector cgroups = Subsystem::getCGroups(pid); + for (const auto& i : cgroups) { + if (utils::beginsWith(i, subsys + ":")) { + return CGroup(i); + } + } + + const std::string msg = "cgroup not found for pid " + std::to_string(pid); + LOGE(msg); + throw CGroupException(msg); +} + } //namespace lxcpp diff --git a/libs/lxcpp/cgroups/cgroup.hpp b/libs/lxcpp/cgroups/cgroup.hpp index f8d5698..c65c12d 100644 --- a/libs/lxcpp/cgroups/cgroup.hpp +++ b/libs/lxcpp/cgroups/cgroup.hpp @@ -65,6 +65,18 @@ public: void destroy(); /** + * Set common 'cgroup' paramter + * Equivalent of: echo value > mSubsys_path/mName/cgroup.param + */ + void setCommonValue(const std::string& param, const std::string& value); + + /** + * Get common 'cgroup' paramter + * Equivalent of: cat mSubsys_path/mName/cgroup.param + */ + std::string getCommonValue(const std::string& param) const; + + /** * Set cgroup parameter to value (name validity depends on subsystem) * Equivalent of: echo value > mSubsys_path/mName/mSubsys_name.param */ @@ -77,10 +89,27 @@ public: std::string getValue(const std::string& param) const; /** - * Assign process to this cgroup (will be removed from previous cgroup automatically) + * Assign all processes in threadgroup of pid to this cgroup + * Equivalent of: echo pid > mSubsys_path/mName/cgroup.procs + */ + void assignGroup(pid_t pid); + + /** + * Assign single process to this cgroup (will be removed from previous cgroup automatically) * Equivalent of: echo pid > mSubsys_path/mName/tasks */ - void assignProcess(pid_t pid); + void assignPid(pid_t pid); + + /** + * Get list of pid assigned to this group + * Equivalent of: cat mSubsys_path/mName/tasks + */ + std::vector getPids() const; + + /** + * Get cgroup of process pid in given subsystem + */ + static CGroup getCGroup(const std::string& subsys, pid_t pid); private: const Subsystem mSubsys; // referred subsystem diff --git a/libs/lxcpp/cgroups/devices.cpp b/libs/lxcpp/cgroups/devices.cpp new file mode 100644 index 0000000..6bf8201 --- /dev/null +++ b/libs/lxcpp/cgroups/devices.cpp @@ -0,0 +1,95 @@ +/* + * 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 Krzysztof Dynowski (k.dynowski@samsumg.com) + * @brief Control-groups management, devices + */ + +#include "lxcpp/cgroups/devices.hpp" +#include "lxcpp/exception.hpp" +#include "utils/text.hpp" +#include "logger/logger.hpp" + +#include + +namespace lxcpp { + +namespace { +std::string devString(int n) +{ + return n >= -1 ? std::to_string(n) : "*"; +} + +DevicePermission& parsePerms(DevicePermission& p,const std::string& line) +{ + std::string re = "^([a-z]) ([0-9]+|\\*):([0-9]+|\\*) ([a-z]+)$"; + std::smatch match; + try { + std::regex rgx(re); + if (!std::regex_search(line, match, rgx)) { + throw CGroupException("wrong input: " + line); + } + } catch (CGroupException) { + throw; + } catch (std::runtime_error e) { + throw std::runtime_error(e.what() + std::string(" update your c++ libs")); + } + + p.type = match.str(1).at(0); + p.major = match.str(2) == "*" ? -1 : std::stoi(match.str(2)); + p.minor = match.str(3) == "*" ? -1 : std::stoi(match.str(3)); + p.permission = match.str(4); + return p; +} + +} //namespace + +void DevicesCGroup::allow(DevicePermission p) +{ + allow(p.type, p.major, p.minor, p.permission); +} + +void DevicesCGroup::deny(DevicePermission p) +{ + deny(p.type, p.major, p.minor, p.permission); +} + +void DevicesCGroup::allow(char type, int major, int minor, const std::string& perm) +{ + setValue("allow", type + std::string(" ") + devString(major) + ":" + devString(minor) + " " + perm); +} + +void DevicesCGroup::deny(char type, int major, int minor, const std::string& perm) +{ + setValue("deny", type + std::string(" ") + devString(major) + ":" + devString(minor) + " " + perm); +} + +std::vector DevicesCGroup::list() +{ + std::vector list; + DevicePermission p; + for (const auto& ln : utils::split(getValue("list"), "\n")) { + if (!ln.empty()) { + list.push_back(parsePerms(p, ln)); + } + } + return list; +} + +} //namespace lxcpp diff --git a/libs/lxcpp/cgroups/devices.hpp b/libs/lxcpp/cgroups/devices.hpp new file mode 100644 index 0000000..83d2fe2 --- /dev/null +++ b/libs/lxcpp/cgroups/devices.hpp @@ -0,0 +1,53 @@ +/* + * 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 Krzysztof Dynowski (k.dynowski@samsumg.com) + * @brief Control-groups management, devices + */ + +#ifndef LXCPP_CGROUPS_DEVICES_HPP +#define LXCPP_CGROUPS_DEVICES_HPP + +#include "lxcpp/cgroups/cgroup.hpp" + +namespace lxcpp { + +struct DevicePermission { + char type; // 'a'==any, 'b'==block, 'c'==character + int major,minor; // -1==any + std::string permission; // combination of "rwm" (r==read,w==write,m==create) +}; + +class DevicesCGroup : public CGroup { +public: + DevicesCGroup(const std::string& name) : + CGroup("devices", name) + { + } + + void allow(DevicePermission p); + void deny(DevicePermission p); + void allow(char type, int major, int minor, const std::string& perm); + void deny(char type, int major, int minor, const std::string& perm); + std::vector list(); +}; + +} //namespace lxcpp + +#endif //LXCPP_CGROUPS_DEVICE_HPP diff --git a/libs/lxcpp/cgroups/subsystem.cpp b/libs/lxcpp/cgroups/subsystem.cpp index dc18683..beb51f9 100644 --- a/libs/lxcpp/cgroups/subsystem.cpp +++ b/libs/lxcpp/cgroups/subsystem.cpp @@ -45,7 +45,6 @@ Subsystem::Subsystem(const std::string& name) : mName(name) throw CGroupException(msg); } - std::vector av = availableSubsystems(); //find mount point for a name std::ifstream fileStream("/proc/mounts"); if (!fileStream.good()) { diff --git a/tests/unit_tests/lxcpp/ut-cgroups.cpp b/tests/unit_tests/lxcpp/ut-cgroups.cpp index 510aba3..bc5be16 100644 --- a/tests/unit_tests/lxcpp/ut-cgroups.cpp +++ b/tests/unit_tests/lxcpp/ut-cgroups.cpp @@ -25,7 +25,9 @@ #include "ut.hpp" #include "logger/logger.hpp" -#include "lxcpp/cgroups/subsystem.hpp" +#include "lxcpp/cgroups/devices.hpp" +#include "lxcpp/exception.hpp" +#include "utils/text.hpp" namespace { @@ -45,10 +47,10 @@ BOOST_AUTO_TEST_CASE(GetAvailable) { std::vector subs; BOOST_CHECK_NO_THROW(subs = Subsystem::availableSubsystems()); - BOOST_CHECK(subs.size() > 0); + BOOST_CHECK_MESSAGE(subs.size() > 0, "Control groups not supported"); for (auto n : subs){ Subsystem s(n); - LOGD(s.getName() << ": " << (s.isAttached()?s.getMountPoint():"[not attached]")); + LOGD(s.getName() << ": " << (s.isAttached() ? s.getMountPoint() : "[not attached]")); } } @@ -59,24 +61,66 @@ BOOST_AUTO_TEST_CASE(GetCGroupsByPid) BOOST_CHECK(cg.size() > 0); } +BOOST_AUTO_TEST_CASE(GetPidsByCGroup) +{ + CGroup cg = CGroup::getCGroup("memory", ::getpid()); + std::vector pids; + BOOST_CHECK_NO_THROW(pids = cg.getPids()); + BOOST_CHECK(pids.size() > 0); +} + BOOST_AUTO_TEST_CASE(SubsysAttach) { Subsystem sub("freezer"); - BOOST_CHECK_MESSAGE(sub.getName() == "freezer", "freezer not equal"); BOOST_CHECK_MESSAGE(sub.isAvailable(), "freezer not found"); if (!sub.isAvailable()) return ; - if (sub.isAttached()) { std::string mp = sub.getMountPoint(); BOOST_CHECK_NO_THROW(Subsystem::detach(mp)); + BOOST_CHECK(Subsystem(sub.getName()).isAttached()==false); BOOST_CHECK_NO_THROW(Subsystem::attach(mp, {sub.getName()})); + BOOST_CHECK(Subsystem(sub.getName()).isAttached()==true); } else { std::string mp = "/sys/fs/cgroup/" + sub.getName(); BOOST_CHECK_NO_THROW(Subsystem::attach(mp, {sub.getName()})); + BOOST_CHECK(Subsystem(sub.getName()).isAttached()==true); BOOST_CHECK_NO_THROW(Subsystem::detach(mp)); + BOOST_CHECK(Subsystem(sub.getName()).isAttached()==false); + } +} + +BOOST_AUTO_TEST_CASE(ControlGroupParams) +{ + CGroup memg("memory:/ut-params"); + BOOST_CHECK(memg.exists() == false); + BOOST_CHECK_NO_THROW(memg.create()); + BOOST_CHECK(memg.exists() == true); + + if (!memg.exists()) return ; + + memg.assignPid(::getpid()); + memg.setValue("limit_in_bytes", "10k"); + memg.setValue("soft_limit_in_bytes", "10k"); + BOOST_CHECK_THROW(memg.setValue("non-existing-name", "xxx"), CGroupException); + + LOGD("limit_in_bytes: " << memg.getValue("limit_in_bytes")); + LOGD("soft_limit_in_bytes: " << memg.getValue("soft_limit_in_bytes")); + LOGD("max_usage_in_bytes: " << memg.getValue("max_usage_in_bytes")); + + CGroup("memory:/").assignPid(::getpid()); + BOOST_CHECK_NO_THROW(memg.destroy()); +} + +BOOST_AUTO_TEST_CASE(DevicesParams) +{ + DevicesCGroup devcg("/"); + std::vector list = devcg.list(); + for (const auto& i : list) { + LOGD(std::string("perm = ") + i.type + " " + + std::to_string(i.major) + ":" + std::to_string(i.minor) + " " + i.permission); } } -- 2.7.4 From a7ae67cc69847a73335b5715cfab8df1be7d54cb Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Wed, 28 Oct 2015 13:27:49 +0100 Subject: [PATCH 13/16] Fix build without systemd. [Feature] Fix build without systemd. [Cause] N/A [Solution] N/A [Verification] Build. Change-Id: I06f9623e34dfc44f6090201fad4b024f2cb29e7c --- libs/ipc/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/ipc/CMakeLists.txt b/libs/ipc/CMakeLists.txt index 9e1e6f9..9a34ea7 100644 --- a/libs/ipc/CMakeLists.txt +++ b/libs/ipc/CMakeLists.txt @@ -45,8 +45,9 @@ SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES ADD_DEPENDENCIES(${PROJECT_NAME} Common) ## Link libraries ############################################################## +PKG_CHECK_MODULES(IPC_DEPS REQUIRED uuid) IF(NOT WITHOUT_SYSTEMD) -PKG_CHECK_MODULES(IPC_DEPS REQUIRED libsystemd-daemon uuid) +PKG_CHECK_MODULES(IPC_DEPS REQUIRED libsystemd-daemon) ENDIF(NOT WITHOUT_SYSTEMD) INCLUDE_DIRECTORIES(${LIBS_FOLDER}) -- 2.7.4 From 2b32511f729dd4a2f9c358973435294477c3b7b3 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Mon, 26 Oct 2015 16:03:46 +0100 Subject: [PATCH 14/16] lxcpp: user namespace setup [Feature] Setting up of a user namespace. This also changes the way namespaces are chosen. This happens automatically now. [Cause] N/A [Solution] N/A [Verification] Run junk tester. Change-Id: I70c57b56c94ed9650208b63831c77f1ad0c7905c --- junk/run-shell.cpp | 8 +++- libs/lxcpp/attach/attach-helper.cpp | 4 +- libs/lxcpp/commands/attach.cpp | 6 +-- libs/lxcpp/commands/attach.hpp | 6 +-- libs/lxcpp/commands/setup-userns.cpp | 84 +++++++++++++++++++++++++++++++++ libs/lxcpp/commands/setup-userns.hpp | 55 +++++++++++++++++++++ libs/lxcpp/container-config.hpp | 12 ++++- libs/lxcpp/container-impl.cpp | 29 +++++++++--- libs/lxcpp/container-impl.hpp | 4 +- libs/lxcpp/container.hpp | 4 +- libs/lxcpp/credentials.cpp | 12 ++--- libs/lxcpp/credentials.hpp | 4 +- libs/lxcpp/exception.hpp | 5 ++ libs/lxcpp/guard/guard.cpp | 48 ++++++++++++++----- libs/lxcpp/guard/guard.hpp | 10 ++++ libs/lxcpp/userns-config.hpp | 70 +++++++++++++++++++++++++++ tests/unit_tests/lxcpp/ut-container.cpp | 1 - 17 files changed, 320 insertions(+), 42 deletions(-) create mode 100644 libs/lxcpp/commands/setup-userns.cpp create mode 100644 libs/lxcpp/commands/setup-userns.hpp create mode 100644 libs/lxcpp/userns-config.hpp diff --git a/junk/run-shell.cpp b/junk/run-shell.cpp index 81ee0d8..cff5dee 100644 --- a/junk/run-shell.cpp +++ b/junk/run-shell.cpp @@ -61,13 +61,17 @@ int main(int argc, char *argv[]) c->setInit(args); c->setLogger(logger::LogType::LOG_FILE, logger::LogLevel::TRACE, "/tmp/lxcpp-shell.txt"); c->setTerminalCount(4); + // make my own user root in a new namespace + c->addUIDMap(0, 1000, 1); + c->addGIDMap(0, 1000, 1); + // make root and system users non privileged ones + c->addUIDMap(1000, 0, 999); + c->addGIDMap(1000, 0, 999); c->start(); c->console(); // You could run the console for the second time to see if it can be reattached //c->console(); - initPid = c->getInitPid(); - delete c; } catch (const std::exception &e) diff --git a/libs/lxcpp/attach/attach-helper.cpp b/libs/lxcpp/attach/attach-helper.cpp index 5aaaecb..addfd37 100644 --- a/libs/lxcpp/attach/attach-helper.cpp +++ b/libs/lxcpp/attach/attach-helper.cpp @@ -61,9 +61,9 @@ int child(void* data) setenv(config.envToSet); // Set uid/gids - lxcpp::setgid(config.gid); + lxcpp::setregid(config.gid, config.gid); setgroups(config.supplementaryGids); - lxcpp::setuid(config.uid); + lxcpp::setreuid(config.uid, config.uid); // Set control TTY if(!setupControlTTY(config.ttyFD)) { diff --git a/libs/lxcpp/commands/attach.cpp b/libs/lxcpp/commands/attach.cpp index a059986..b7201fb 100644 --- a/libs/lxcpp/commands/attach.cpp +++ b/libs/lxcpp/commands/attach.cpp @@ -33,7 +33,7 @@ namespace lxcpp { -Attach::Attach(const lxcpp::ContainerImpl& container, +Attach::Attach(const ContainerConfig& config, const std::vector& argv, const uid_t uid, const gid_t gid, @@ -45,8 +45,8 @@ Attach::Attach(const lxcpp::ContainerImpl& container, const std::vector>& envToSet) : mIntermChannel(false), mConfig(argv, - container.getInitPid(), - container.getNamespaces(), + config.mInitPid, + config.mNamespaces, uid, gid, supplementaryGids, diff --git a/libs/lxcpp/commands/attach.hpp b/libs/lxcpp/commands/attach.hpp index 123a384..34945df 100644 --- a/libs/lxcpp/commands/attach.hpp +++ b/libs/lxcpp/commands/attach.hpp @@ -44,7 +44,7 @@ public: * Object attach should be used immediately after creation. * It will not be stored for future use like most other commands. * - * @param container container to which it attaches + * @param config config of a container to which it attaches * @param argv path and arguments for the user's executable * @param uid uid in the container * @param gid gid in the container @@ -55,7 +55,7 @@ public: * @param envToKeep environment variables that will be kept * @param envToSet new environment variables that will be set */ - Attach(const lxcpp::ContainerImpl& container, + Attach(const ContainerConfig& config, const std::vector& argv, const uid_t uid, const gid_t gid, @@ -79,4 +79,4 @@ private: } // namespace lxcpp -#endif // LXCPP_COMMANDS_ATTACH_HPP \ No newline at end of file +#endif // LXCPP_COMMANDS_ATTACH_HPP diff --git a/libs/lxcpp/commands/setup-userns.cpp b/libs/lxcpp/commands/setup-userns.cpp new file mode 100644 index 0000000..c9491b5 --- /dev/null +++ b/libs/lxcpp/commands/setup-userns.cpp @@ -0,0 +1,84 @@ +/* + * 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 user namespace setup + */ + +#include "lxcpp/commands/setup-userns.hpp" + +#include "logger/logger.hpp" +#include "utils/fs.hpp" + +#include +#include + + +namespace lxcpp { + + +SetupUserNS::SetupUserNS(UserNSConfig &userNSConfig, pid_t initPid) + : mUserNSConfig(userNSConfig), + mInitPid(initPid) +{ +} + +SetupUserNS::~SetupUserNS() +{ +} + +void SetupUserNS::execute() +{ + const std::string proc = "/proc/" + std::to_string(mInitPid); + const std::string uid_map_path = proc + "/uid_map"; + const std::string gid_map_path = proc + "/gid_map"; + + std::string uid_map; + for (const auto map : mUserNSConfig.mUIDMaps) { + uid_map.append(std::to_string(map.min)); + uid_map.append(" "); + uid_map.append(std::to_string(map.max)); + uid_map.append(" "); + uid_map.append(std::to_string(map.num)); + uid_map.append("\n"); + } + if (uid_map.size() && !utils::saveFileContent(uid_map_path, uid_map)) { + const std::string msg = "Failed to write the uid_map"; + LOGE(msg); + throw UserNSException(msg); + } + + std::string gid_map; + for (const auto map : mUserNSConfig.mGIDMaps) { + gid_map.append(std::to_string(map.min)); + gid_map.append(" "); + gid_map.append(std::to_string(map.max)); + gid_map.append(" "); + gid_map.append(std::to_string(map.num)); + gid_map.append("\n"); + } + if (gid_map.size() && !utils::saveFileContent(gid_map_path, gid_map)) { + const std::string msg = "Failed to write the gid_map"; + LOGE(msg); + throw UserNSException(msg); + } +} + + +} // namespace lxcpp diff --git a/libs/lxcpp/commands/setup-userns.hpp b/libs/lxcpp/commands/setup-userns.hpp new file mode 100644 index 0000000..cb4680d --- /dev/null +++ b/libs/lxcpp/commands/setup-userns.hpp @@ -0,0 +1,55 @@ +/* + * 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 of user namespace setup + */ + +#ifndef LXCPP_COMMANDS_SETUP_USERNS_HPP +#define LXCPP_COMMANDS_SETUP_USERNS_HPP + +#include "lxcpp/commands/command.hpp" +#include "lxcpp/container-config.hpp" + + +namespace lxcpp { + + +class SetupUserNS final: Command { +public: + /** + * Setups the user namespace by filling UID/GID mappings + * + * @param userNSConfig A config containing UID and GID mappings + */ + SetupUserNS(UserNSConfig &userNSConfig, pid_t initPid); + ~SetupUserNS(); + + void execute(); + +private: + UserNSConfig &mUserNSConfig; + pid_t mInitPid; +}; + + +} // namespace lxcpp + + +#endif // LXCPP_COMMANDS_SETUP_USERNS_HPP diff --git a/libs/lxcpp/container-config.hpp b/libs/lxcpp/container-config.hpp index 1a487cf..05f11ed 100644 --- a/libs/lxcpp/container-config.hpp +++ b/libs/lxcpp/container-config.hpp @@ -28,6 +28,7 @@ #include "lxcpp/network-config.hpp" #include "lxcpp/terminal-config.hpp" #include "lxcpp/provision-config.hpp" +#include "lxcpp/userns-config.hpp" #include #include @@ -126,6 +127,14 @@ struct ContainerConfig { */ ProvisionConfig mProvisions; + /** + * User namespace config (uid and gid mappings) + * + * Set: addUIDMap(), addGIDMap() + * Get: none + */ + UserNSConfig mUserNSConfig; + ContainerConfig() : mGuardPid(-1), mInitPid(-1), mNamespaces(0) {} CONFIG_REGISTER @@ -138,7 +147,8 @@ struct ContainerConfig { mLogger, mTerminals, mNamespaces, - mProvisions + mProvisions, + mUserNSConfig ) }; diff --git a/libs/lxcpp/container-impl.cpp b/libs/lxcpp/container-impl.cpp index 29d6cb0..33331a2 100644 --- a/libs/lxcpp/container-impl.cpp +++ b/libs/lxcpp/container-impl.cpp @@ -72,6 +72,7 @@ ContainerImpl::ContainerImpl(const std::string &name, const std::string &path) mConfig.mName = name; mConfig.mRootPath = path; + mConfig.mNamespaces = CLONE_NEWIPC | CLONE_NEWNS | CLONE_NEWPID | CLONE_NEWUTS; } // TODO: the aim of this constructor is to create a new ContainerImpl based on an already @@ -147,15 +148,30 @@ void ContainerImpl::setTerminalCount(const unsigned int count) mConfig.mTerminals.count = count; } -void ContainerImpl::setNamespaces(const int namespaces) +void ContainerImpl::addUIDMap(unsigned min, unsigned max, unsigned num) { - mConfig.mNamespaces = namespaces; -} + mConfig.mNamespaces |= CLONE_NEWUSER; + + if (mConfig.mUserNSConfig.mUIDMaps.size() >= 5) { + const std::string msg = "Max number of 5 UID mappings has been already reached"; + LOGE(msg); + throw ConfigureException(msg); + } + mConfig.mUserNSConfig.mUIDMaps.emplace_back(min, max, num); +} -int ContainerImpl::getNamespaces() const +void ContainerImpl::addGIDMap(unsigned min, unsigned max, unsigned num) { - return mConfig.mNamespaces; + mConfig.mNamespaces |= CLONE_NEWUSER; + + if (mConfig.mUserNSConfig.mGIDMaps.size() >= 5) { + const std::string msg = "Max number of 5 GID mappings has been already reached"; + LOGE(msg); + throw ConfigureException(msg); + } + + mConfig.mUserNSConfig.mGIDMaps.emplace_back(min, max, num); } void ContainerImpl::start() @@ -196,7 +212,7 @@ void ContainerImpl::reboot() void ContainerImpl::attach(const std::vector& argv, const std::string& cwdInContainer) { - Attach attach(*this, + Attach attach(mConfig, argv, /*uid in container*/ 0, /*gid in container*/ 0, @@ -228,6 +244,7 @@ void ContainerImpl::addInterfaceConfig(const std::string& hostif, const std::vector& addrs, MacVLanMode mode) { + mConfig.mNamespaces |= CLONE_NEWNET; mConfig.mNetwork.addInterfaceConfig(hostif, zoneif, type, addrs, mode); } diff --git a/libs/lxcpp/container-impl.hpp b/libs/lxcpp/container-impl.hpp index f1cba58..a759929 100644 --- a/libs/lxcpp/container-impl.hpp +++ b/libs/lxcpp/container-impl.hpp @@ -55,8 +55,8 @@ public: void setTerminalCount(const unsigned int count); - void setNamespaces(const int namespaces); - int getNamespaces() const; + void addUIDMap(unsigned min, unsigned max, unsigned num); + void addGIDMap(unsigned min, unsigned max, unsigned num); // Execution actions void start(); diff --git a/libs/lxcpp/container.hpp b/libs/lxcpp/container.hpp index 2d0e696..bc43066 100644 --- a/libs/lxcpp/container.hpp +++ b/libs/lxcpp/container.hpp @@ -65,8 +65,8 @@ public: virtual void setTerminalCount(const unsigned int count) = 0; - virtual void setNamespaces(const int namespaces) = 0; - virtual int getNamespaces() const = 0; + virtual void addUIDMap(unsigned min, unsigned max, unsigned num) = 0; + virtual void addGIDMap(unsigned min, unsigned max, unsigned num) = 0; // Execution actions virtual void start() = 0; diff --git a/libs/lxcpp/credentials.cpp b/libs/lxcpp/credentials.cpp index c127170..10b477d 100644 --- a/libs/lxcpp/credentials.cpp +++ b/libs/lxcpp/credentials.cpp @@ -42,20 +42,20 @@ void setgroups(const std::vector& gids) } } -void setgid(const gid_t gid) +void setregid(const gid_t rgid, const gid_t egid) { - if(-1 == ::setgid(gid)) { - const std::string msg = "setgid() failed: " + + if(-1 == ::setregid(rgid, egid)) { + const std::string msg = "setregid() failed: " + utils::getSystemErrorMessage(); LOGE(msg); throw CredentialSetupException(msg); } } -void setuid(const uid_t uid) +void setreuid(const uid_t ruid, const uid_t euid) { - if(-1 == ::setuid(uid)) { - const std::string msg = "setuid() failed: " + + if(-1 == ::setreuid(ruid, euid)) { + const std::string msg = "setreuid() failed: " + utils::getSystemErrorMessage(); LOGE(msg); throw CredentialSetupException(msg); diff --git a/libs/lxcpp/credentials.hpp b/libs/lxcpp/credentials.hpp index aa56aca..e5be25d 100644 --- a/libs/lxcpp/credentials.hpp +++ b/libs/lxcpp/credentials.hpp @@ -32,9 +32,9 @@ namespace lxcpp { void setgroups(const std::vector& groups); -void setgid(const gid_t gid); +void setregid(const gid_t rgid, const gid_t egid); -void setuid(const uid_t uid); +void setreuid(const uid_t ruid, const uid_t euid); pid_t setsid(); diff --git a/libs/lxcpp/exception.hpp b/libs/lxcpp/exception.hpp index 061bc6c..3ecd5ba 100644 --- a/libs/lxcpp/exception.hpp +++ b/libs/lxcpp/exception.hpp @@ -106,6 +106,11 @@ struct ProvisionException: public Exception { : Exception(message) {} }; +struct UserNSException: public Exception { + explicit UserNSException(const std::string& message = "User namespace error") + : Exception(message) {} +}; + } // namespace lxcpp #endif // LXCPP_EXCEPTION_HPP diff --git a/libs/lxcpp/guard/guard.cpp b/libs/lxcpp/guard/guard.cpp index bc5f112..8a9f173 100644 --- a/libs/lxcpp/guard/guard.cpp +++ b/libs/lxcpp/guard/guard.cpp @@ -24,8 +24,10 @@ #include "lxcpp/utils.hpp" #include "lxcpp/guard/guard.hpp" #include "lxcpp/process.hpp" +#include "lxcpp/credentials.hpp" #include "lxcpp/commands/prep-guest-terminal.hpp" #include "lxcpp/commands/provision.hpp" +#include "lxcpp/commands/setup-userns.hpp" #include "config/manager.hpp" #include "logger/logger.hpp" @@ -35,13 +37,17 @@ namespace lxcpp { -namespace { - -int startContainer(void* data) +int Guard::startContainer(void* data) { - ContainerConfig& config = *static_cast(data); + ContainerConfig& config = static_cast(data)->mConfig; + utils::Channel& channel = static_cast(data)->mChannel; + + // wait for continue sync from guard + channel.setRight(); + channel.read(); + channel.shutdown(); - // TODO: container preparation part 2 + // TODO: container preparation part 3: things to do in the container process Provisions provisions(config); provisions.execute(); @@ -49,14 +55,18 @@ int startContainer(void* data) PrepGuestTerminal terminals(config.mTerminals); terminals.execute(); + if (config.mUserNSConfig.mUIDMaps.size()) { + lxcpp::setreuid(0, 0); + } + if (config.mUserNSConfig.mGIDMaps.size()) { + lxcpp::setregid(0, 0); + } + lxcpp::execve(config.mInit); return EXIT_FAILURE; } -} // namespace - - Guard::Guard(const int channelFD) : mChannel(channelFD) { @@ -85,10 +95,13 @@ Guard::~Guard() int Guard::execute() { - // TODO: container preparation part 1 + // TODO: container preparation part 1: things to do before clone + + utils::Channel channel; + ContainerData data(mConfig, channel); - const pid_t initPid = lxcpp::clone(startContainer, - &mConfig, + const pid_t initPid = lxcpp::clone(Guard::startContainer, + &data, mConfig.mNamespaces); mConfig.mGuardPid = ::getpid(); @@ -98,10 +111,21 @@ int Guard::execute() mChannel.write(mConfig.mInitPid); mChannel.shutdown(); + // TODO: container preparation part 2: things to do immediately after clone + + SetupUserNS userNS(mConfig.mUserNSConfig, mConfig.mInitPid); + userNS.execute(); + + // send continue sync to container once userns, netns, cgroups, etc, are configured + channel.setLeft(); + channel.write(true); + channel.shutdown(); + int status = lxcpp::waitpid(initPid); LOGD("Init exited with status: " << status); - // TODO: cleanup after child exits + // TODO: container (de)preparation part 4: cleanup after container quits + Provisions provisions(mConfig); provisions.revert(); diff --git a/libs/lxcpp/guard/guard.hpp b/libs/lxcpp/guard/guard.hpp index 741d72a..fb53546 100644 --- a/libs/lxcpp/guard/guard.hpp +++ b/libs/lxcpp/guard/guard.hpp @@ -39,6 +39,16 @@ public: int execute(); private: + struct ContainerData { + ContainerConfig &mConfig; + utils::Channel &mChannel; + + ContainerData(ContainerConfig &config, utils::Channel &channel) + : mConfig(config), mChannel(channel) {} + }; + + static int startContainer(void *data); + utils::Channel mChannel; ContainerConfig mConfig; }; diff --git a/libs/lxcpp/userns-config.hpp b/libs/lxcpp/userns-config.hpp new file mode 100644 index 0000000..e560078 --- /dev/null +++ b/libs/lxcpp/userns-config.hpp @@ -0,0 +1,70 @@ +/* + * 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 User namespace configuration + */ + +#ifndef LXCPP_USERNS_CONFIG_HPP +#define LXCPP_USERNS_CONFIG_HPP + +#include "config/config.hpp" +#include "config/fields.hpp" + +#include +#include + + +namespace lxcpp { + + +struct UserNSConfig { + // TODO: Replace UserNSMap with std::tuple + struct UserNSMap { + unsigned min; + unsigned max; + unsigned num; + + UserNSMap() = default; + UserNSMap(unsigned min, unsigned max, unsigned num) + : min(min), max(max), num(num) {} + + CONFIG_REGISTER + ( + min, + max, + num + ) + }; + + std::vector mUIDMaps; + std::vector mGIDMaps; + + CONFIG_REGISTER + ( + mUIDMaps, + mGIDMaps + ) +}; + + +} //namespace lxcpp + + +#endif // LXCPP_USERNS_CONFIG_HPP diff --git a/tests/unit_tests/lxcpp/ut-container.cpp b/tests/unit_tests/lxcpp/ut-container.cpp index 17eee93..1c1a76c 100644 --- a/tests/unit_tests/lxcpp/ut-container.cpp +++ b/tests/unit_tests/lxcpp/ut-container.cpp @@ -116,7 +116,6 @@ BOOST_AUTO_TEST_CASE(StartStop) BOOST_CHECK_NO_THROW(c->setLogger(logger::LogType::LOG_PERSISTENT_FILE, logger::LogLevel::DEBUG, LOGGER_FILE)); - BOOST_CHECK_NO_THROW(c->setNamespaces(CLONE_NEWIPC | CLONE_NEWNET | CLONE_NEWPID | CLONE_NEWUTS)); BOOST_CHECK_NO_THROW(c->start()); BOOST_CHECK_NO_THROW(c->stop()); } -- 2.7.4 From bb88bd288e6e5522157a988d829247d0a520a245 Mon Sep 17 00:00:00 2001 From: Lukasz Pawelczyk Date: Wed, 28 Oct 2015 13:37:05 +0100 Subject: [PATCH 15/16] logger: set thread id column width to 2 [Feature] Thread ID is often 2 digit number, reflect that [Cause] N/A [Solution] N/A [Verification] Run some tests and verify visually Change-Id: Iec1ddbb5bc3e28fc0c2ac199cbdf673348405537 --- libs/logger/formatter.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/logger/formatter.cpp b/libs/logger/formatter.cpp index 06404f2..6733ade 100644 --- a/libs/logger/formatter.cpp +++ b/libs/logger/formatter.cpp @@ -40,7 +40,8 @@ namespace { const int TIME_COLUMN_LENGTH = 12; const int SEVERITY_COLUMN_LENGTH = 8; -const int PROCESS_COLUMN_LENGTH = 8; +const int PID_COLUMN_LENGTH = 8; +const int TID_COLUMN_LENGTH = 2; const int FILE_COLUMN_LENGTH = 60; std::atomic gNextThreadId(1); @@ -123,7 +124,8 @@ std::string LogFormatter::getHeader(LogLevel logLevel, std::ostringstream logLine; logLine << getCurrentTime() << ' ' << std::left << std::setw(SEVERITY_COLUMN_LENGTH) << '[' + toString(logLevel) + ']' - << std::right << std::setw(PROCESS_COLUMN_LENGTH) << ::getpid() << "/" << getCurrentThread() << ": " + << std::right << std::setw(PID_COLUMN_LENGTH) << ::getpid() << "/" + << std::right << std::setw(TID_COLUMN_LENGTH) << getCurrentThread() << ": " << std::left << std::setw(FILE_COLUMN_LENGTH) << file + ':' + std::to_string(line) + ' ' + func + ':'; return logLine.str(); -- 2.7.4 From 92b8bac68d19641ddc8fa7ba07f80e80199a31cc Mon Sep 17 00:00:00 2001 From: Dariusz Michaluk Date: Tue, 27 Oct 2015 14:39:54 +0100 Subject: [PATCH 16/16] Remove wrapper. Old API is not supported anymore. [Feature] Remove wrapper. Old API is not supported anymore. Fix release build. [Cause] N/A [Solution] N/A [Verification] Build. Change-Id: Ibd3378dee3b7597d7d27c2b8e0a963167d9b296f --- CMakeLists.txt | 2 - client/vasum-client.h | 4 - packaging/vasum.spec | 9 +- tests/cppcheck/cppcheck.suppress | 2 - tests/unit_tests/lxcpp/ut-cgroups.cpp | 2 +- wrapper/CMakeLists.txt | 76 -- wrapper/vasum.h | 999 -------------------- wrapper/vasum.pc.in | 12 - wrapper/vasum_list.h | 102 -- wrapper/wrapper-compatibility.cpp | 1671 --------------------------------- wrapper/wrapper-compatibility.h | 152 --- wrapper/wrapper.cpp | 818 ---------------- 12 files changed, 3 insertions(+), 3846 deletions(-) delete mode 100644 wrapper/CMakeLists.txt delete mode 100644 wrapper/vasum.h delete mode 100644 wrapper/vasum.pc.in delete mode 100644 wrapper/vasum_list.h delete mode 100644 wrapper/wrapper-compatibility.cpp delete mode 100644 wrapper/wrapper-compatibility.h delete mode 100644 wrapper/wrapper.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c0c800c..b1b6ed5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -155,7 +155,6 @@ SET(ZONE_SUPPORT_FOLDER ${PROJECT_SOURCE_DIR}/zone-support) SET(ZONE_DAEMON_FOLDER ${PROJECT_SOURCE_DIR}/zone-daemon) SET(TESTS_FOLDER ${PROJECT_SOURCE_DIR}/tests) SET(CLI_FOLDER ${PROJECT_SOURCE_DIR}/cli) -SET(WRAPPER_FOLDER ${PROJECT_SOURCE_DIR}/wrapper) IF(NOT DEFINED SYSCONF_INSTALL_DIR) @@ -210,4 +209,3 @@ ADD_SUBDIRECTORY(${ZONE_DAEMON_FOLDER}) ENDIF(NOT WITHOUT_DBUS) ADD_SUBDIRECTORY(${TESTS_FOLDER}) ADD_SUBDIRECTORY(${CLI_FOLDER}) -ADD_SUBDIRECTORY(${WRAPPER_FOLDER}) diff --git a/client/vasum-client.h b/client/vasum-client.h index 253306d..47bac7b 100644 --- a/client/vasum-client.h +++ b/client/vasum-client.h @@ -257,8 +257,6 @@ typedef enum { VSMDISPATCHER_INTERNAL /**< Library will take care of dispatching messages */ } VsmDispacherType; -#ifndef __VASUM_WRAPPER_SOURCE__ - /** * Get file descriptor associated with event dispatcher of zone client * @@ -986,8 +984,6 @@ const void *vsm_addrlist_get_addr(VsmAddrList addrs, unsigned int i); */ unsigned int vsm_addrlist_get_prefix(VsmAddrList addrs, unsigned int i); -#endif /* __VASUM_WRAPPER_SOURCE__ */ - #ifdef __cplusplus } #endif diff --git a/packaging/vasum.spec b/packaging/vasum.spec index 447bbcf..7249493 100644 --- a/packaging/vasum.spec +++ b/packaging/vasum.spec @@ -44,7 +44,7 @@ Requires: lxc-templates Requires: iproute Requires(post): libcap %endif -Obsoletes: vasum-daemon < 1:0 +Conflicts: vasum-daemon < 1:0 %description This package provides a daemon used to manage zones - start, stop and switch @@ -154,7 +154,7 @@ fi Summary: Vasum Client Group: Development/Libraries Requires: vasum = %{epoch}:%{version}-%{release} -Obsoletes: vasum < 1:0 +Conflicts: vasum < 1:0 Requires(post): /sbin/ldconfig Requires(postun): /sbin/ldconfig @@ -172,9 +172,6 @@ Library interface to the vasum daemon %defattr(644,root,root,755) %attr(755,root,root) %{_libdir}/libvasum-client.so.%{version} %{_libdir}/libvasum-client.so.0 -%attr(755,root,root) %{_libdir}/libvasum.so.%{version} -%{_libdir}/libvasum.so.0 - ## Devel Package ############################################################### %package devel @@ -192,10 +189,8 @@ Development package including the header files for the client library %endif %defattr(644,root,root,755) %{_libdir}/libvasum-client.so -%{_libdir}/libvasum.so %{_includedir}/vasum %{_libdir}/pkgconfig/vasum-client.pc -%{_libdir}/pkgconfig/vasum.pc %if !%{without_dbus} ## Zone Support Package ################################################### diff --git a/tests/cppcheck/cppcheck.suppress b/tests/cppcheck/cppcheck.suppress index 8d7380b..097496a 100644 --- a/tests/cppcheck/cppcheck.suppress +++ b/tests/cppcheck/cppcheck.suppress @@ -1,6 +1,4 @@ // 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 diff --git a/tests/unit_tests/lxcpp/ut-cgroups.cpp b/tests/unit_tests/lxcpp/ut-cgroups.cpp index bc5be16..5bde171 100644 --- a/tests/unit_tests/lxcpp/ut-cgroups.cpp +++ b/tests/unit_tests/lxcpp/ut-cgroups.cpp @@ -118,7 +118,7 @@ BOOST_AUTO_TEST_CASE(DevicesParams) { DevicesCGroup devcg("/"); std::vector list = devcg.list(); - for (const auto& i : list) { + for (__attribute__((unused)) const auto& i : list) { LOGD(std::string("perm = ") + i.type + " " + std::to_string(i.major) + ":" + std::to_string(i.minor) + " " + i.permission); } diff --git a/wrapper/CMakeLists.txt b/wrapper/CMakeLists.txt deleted file mode 100644 index 7e70765..0000000 --- a/wrapper/CMakeLists.txt +++ /dev/null @@ -1,76 +0,0 @@ -# Copyright (c) 2014 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 Mateusz Malicki (m.malicki2@samsung.com) -# - -PROJECT(vasum) -MESSAGE(STATUS "") -MESSAGE(STATUS "Generating makefile for the Vasum wrapper...") - -## set wrapper library sources (without vasum-client.cpp) -FILE(GLOB wrapper_SRCS *.cpp *.hpp *.h - ${CLIENT_FOLDER}/vasum-client-impl.hpp ${CLIENT_FOLDER}/vasum-client-impl.cpp - ${CLIENT_FOLDER}/host-ipc-connection.hpp ${CLIENT_FOLDER}/host-ipc-connection.cpp - ${CLIENT_FOLDER}/utils.hpp ${CLIENT_FOLDER}/utils.cpp) - -SET(_LIB_VERSION_ "${VERSION}") -SET(_LIB_SOVERSION_ "0") -SET(PC_FILE "${PROJECT_NAME}.pc") - -## Set the default ELF image symbol visibility to hidden. Using this feature -## can very substantially improve linking and load times of shared object -## libraries, produce more optimized code, provide near-perfect API export -## and prevent symbol clashes -ADD_DEFINITIONS(-fvisibility=hidden) -ADD_DEFINITIONS(-D__STDC_FORMAT_MACROS) - -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) -INCLUDE_DIRECTORIES(SYSTEM ${LIB_DEPS_INCLUDE_DIRS} ${Boost_INCLUDE_DIRS} ${JSON_C_INCLUDE_DIRS}) -INCLUDE_DIRECTORIES(${COMMON_FOLDER}) -INCLUDE_DIRECTORIES(${LIBS_FOLDER}) -INCLUDE_DIRECTORIES(${SERVER_FOLDER}) -INCLUDE_DIRECTORIES(${CLIENT_FOLDER}) - -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) - -## Generate the pc file ######################################################## -CONFIGURE_FILE(${PC_FILE}.in ${CMAKE_BINARY_DIR}/${PC_FILE} @ONLY) - - -## Install ##################################################################### -INSTALL(FILES ${CMAKE_BINARY_DIR}/${PC_FILE} - DESTINATION ${LIB_INSTALL_DIR}/pkgconfig) - -INSTALL(TARGETS ${PROJECT_NAME} - DESTINATION ${LIB_INSTALL_DIR} - COMPONENT RuntimeLibraries) - -INSTALL(FILES vasum.h vasum_list.h - DESTINATION ${INCLUDE_INSTALL_DIR}/${PROJECT_NAME}) diff --git a/wrapper/vasum.h b/wrapper/vasum.h deleted file mode 100644 index 0cb245e..0000000 --- a/wrapper/vasum.h +++ /dev/null @@ -1,999 +0,0 @@ -/* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved - * - * Contact: Krzysztof Dynowski - * - * 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 Krzysztof Dynowski (k.dynowski@samsung.com) - * @brief Vasum old API - */ - -#ifndef __VASUM_H__ -#define __VASUM_H__ - -#include -#include -#include -#include -#include - -#include "vasum_list.h" - -#ifndef API -#define API __attribute__((visibility("default"))) -#endif // API - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * - * Revision History: - * - */ - -/** - * @addtogroup CONTEXT vasum context - * @{ -*/ - -/** - *@brief vasum handle for interact with vasum server process. This is opaque data type. - */ -typedef struct vsm_context* vsm_context_h; - -/** - * @brief Create vsm context - * \par Description: - * The vsm context is an abstraction of the logical connection between the zone controller and it's clients. - * and vsm_context_h object should be finalized when interaction with the vasum server is no longer required.\n - * \return An instance of vsm context on success, or NULL - * \retval vsm_context_h successful - * \retval NULL get vasum context failed. - * \par Known issues/bugs: - * Only a host process has permission for vsm_create_context(); - * \pre vsm-zone-svc must be started - * \see vsm_cleanup_context() -*/ -API vsm_context_h vsm_create_context(void); - -/** - * @brief Cleanup zone control context - * \par Description: - * vsm_cleanup_context() finalizes vsm context and release all resources allocated to the vsm context.\n - * This function should be called if interaction with the zone controller is no longer required. - * \param[in] ctx vsm context - * \return #VSM_ERROR_NONE on success. - * \pre vsm_context_h must be initialized by vsm_create_context() - * \post vsm context_h will not be valid after calling this API - * \see vsm_create_context() -*/ -API int vsm_cleanup_context(vsm_context_h ctx); - -/** - * @brief Get file descriptor associated with event dispatcher of zone control context - * \par Description: - * The function vsm_get_poll_fd() returns the file descriptor associated with the event dispatcher of vsm context.\n - * The file descriptor can be bound to another I/O multiplexing facilities like epoll, select, and poll. - * \param[in] ctx vsm context - * \return On success, a nonnegative file descriptor is returned. On negative error code is returned. - * \retval fd nonnegative integer fd value for getting vasum event and refresh vsm_context_h. - * \retval #VSM_ERROR_INVALID invalid vsm_context_h - * \pre vsm_context_h must be initialized by vsm_create_context() - * \see vsm_create_context() -*/ -API int vsm_get_poll_fd(vsm_context_h ctx); - -/** - * @brief Wait for an I/O event on a VSM context - * \par Description: - * vsm_enter_eventloop() waits for event on the vsm context.\n - *\n - * The call waits for a maximum time of timout milliseconds. Specifying a timeout of -1 makes vsm_enter_eventloop() wait indefinitely, - * while specifying a timeout equal to zero makes vsm_enter_eventloop() to return immediately even if no events are available. - * \param[in] ctx vsm context - * \param[in] flags Reserved - * \param[in] timeout Timeout time (milisecond), -1 is infinite - * \return 0 on success, or negative error code. - * \pre vsm context must be initialized by vsm_create_context() - * \see vsm_create_context(), vsm_get_poll_fd() -*/ -API int vsm_enter_eventloop(vsm_context_h ctx, int flags, int timeout); - -/** - * @brief Enumeration for vasum error. - */ -typedef enum { - VSM_ERROR_NONE, /**< The operation was successful */ - VSM_ERROR_GENERIC, /**< Non-specific cause */ - VSM_ERROR_INVALID, /**< Invalid argument */ - VSM_ERROR_CANCELED, /**< The requested operation was cancelled */ - VSM_ERROR_ABORTED, /**< Operation aborted */ - VSM_ERROR_REFUSED, /**< Connection refused */ - VSM_ERROR_EXIST, /**< Target exists */ - VSM_ERROR_BUSY, /**< Resource is busy */ - VSM_ERROR_IO, /**< I/O error*/ - VSM_ERROR_TIMEOUT, /**< Timer expired */ - VSM_ERROR_OVERFLOW, /**< Value too large to be stored in data type */ - VSM_ERROR_OUT_OF_MEMORY, /**< No memory space */ - VSM_ERROR_OUT_OF_RANGE, /**< Input is out of range */ - VSM_ERROR_NOT_PERMITTED, /**< Operation not permitted */ - VSM_ERROR_NOT_IMPLEMENTED, /**< Function is not implemented yet */ - VSM_ERROR_NOT_SUPPORTED, /**< Operation is not supported */ - VSM_ERROR_ACCESS_DENIED, /**< Access privilege is not sufficient */ - VSM_ERROR_NO_OBJECT, /**< Object not found */ - VSM_ERROR_BAD_STATE, /**< Bad state */ - VSM_MAX_ERROR = VSM_ERROR_BAD_STATE -}vsm_error_e; - -/** - * @brief Get last vasum error code from vsm_context. - * \param[in] ctx vsm context - * \return vasum error enum value. - * \par Known issues/bugs: - * thread non-safe - * \see vsm_error_string() -*/ -API vsm_error_e vsm_last_error(vsm_context_h ctx); - -/** - * @brief Get vasum error string. - * \par Description: - * return string pointer for vasum error string. - * \param[in] error vsm_error_e. - * \return string pointer value represent to error code. - * \warning Do not free returned pointer. -*/ -API const char *vsm_error_string(vsm_error_e error); - -/// @} - -/** - * @addtogroup LIFECYCLE Vasum Lifecycle - * @{ - */ - -/** - * @brief vsm_zone_h opaque datatype which is used to represent an instance of zone. - */ - -typedef struct vsm_zone* vsm_zone_h; - -/** - * @brief Definition for default zone name. - * Default zone is started at boot sequence by systemd. -*/ -#define VSM_DEFAULT_ZONE "personal" - - -/** - * @brief Create a new persistent zone - * \par Description: - * vsm_create_zone() triggers zone controller to create new persistent zone.\n\n - * The zone controller distinguishes two types of zones: peristent and transient. - * Persistent zones exist indefinitely in storage. - * While, transient zones are created and started on-the-fly.\n\n - * Creating zone requires template.\n - * In general, creating a zone involves constructing root file filesystem and - * generating configuration files which is used to feature the zone. - * Moreover, it often requires downloading tools and applications pages, - * which are not available in device. - * In that reason, Vasum Framework delegates this work to templates. - * \param[in] ctx vsm context - * \param[in] zone_name zone name - * \param[in] template_name template name to be used for constructing the zone - * \param[in] flag Reserved - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_INVALID Invalid arguments - * \retval #VSM_ERROR_EXIST The same name zone is existed. - * \retval #VSM_ERROR_GENERIC Lxc failed to create zone. - * \retval #VSM_ERROR_IO Database access failed -*/ -API int vsm_create_zone(vsm_context_h ctx, const char *zone_name, const char *template_name, int flag); - -/** - * @brief Destroy persistent zone - * \par Description: - * The function vsm_destroy_zone() triggers zone controller to destroy persistent zone corresponding to the given name.\n - * All data stored in the repository of the zone are also deleted if force argument is set. - * Once the zone repository is deleted, it cannot be recovered. - * \param[in] ctx vsm context - * \param[in] zone_name zone name - * \param[in] force forced flags - * - 0 : do not destory running zone. - * - non-zero : if zone is running, shutdown forcefully, and destroy. - * \return 0 on success, or negative integer error code on error.i - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_BUSY Target zone is running - * \retval #VSM_ERROR_NO_OBJECT Target zone does not exist - * \retval #VSM_ERROR_GENERIC Lxc failed to destroy zone - * \retval #VSM_ERROR_IO Database access failed -*/ -API int vsm_destroy_zone(vsm_context_h ctx, const char *zone_name, int force); - -/** - * @brief Start an execution of a persistent zone - * \par Description: - * The function vsm_start_zone() triggers zone controller to start zone corresponding to the given name.\n - * Caller can speficy the type of zones: transient and peristent. - * Persistent zones need to be defined before being start up(see vsm_create_zone()) - * While, transient zones are created and started on-the-fly. - * \param[in] ctx vsm context - * \param[in] zone_name zone name - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_INVALID Invalid argument. - * \retval #VSM_ERROR_BUSY Target zone is already running state. - * \retval #VSM_ERROR_NO_OBJECT Target zone does not exist - * \retval #VSM_ERROR_GENERIC Lxc failed to start zone -*/ -API int vsm_start_zone(vsm_context_h ctx, const char *zone_name); - -/** - * @brief Stop an execution of running zone - * \par Description: - * Send request to stop running zone.\n - * \param[in] ctx vsm context - * \param[in] zone_name zone name - * \param[in] force option to shutdown. - * - 0 : send SIGPWR signal to init process of target zone. - * - non-zero : terminate all processes in target zone. - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_INVALID Invalid argument. - * \retval #VSM_ERROR_BAD_STATE Failed to lookup running zone. - * \retval #VSM_ERROR_NO_OBJECT Target zone does not exist - * \retval #VSM_ERROR_GENERIC Lxc failed to destroy zone -*/ -API int vsm_shutdown_zone(vsm_context_h ctx, const char *zone_name, int force); - -/** - * @brief Shutdown zone and prevent starting zone - * \par Description: - * Prevent starting target zone. - * If target zone is running, shutdown the zone first. - * \param[in] ctx vsm context - * \param[in] zone_name zone name - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_NO_OBJECT Target zone does not exist - * \retval #VSM_ERROR_GENERIC Locking failed. -*/ -API int vsm_lock_zone(vsm_context_h ctx, const char *zone_name, int shutdown); - -/** - * @brief Allow a zone to be launched - * \par Description: - * Remove lock applied to the zone corresponding to the given name. - * \param[in] ctx vsm context - * \param[in] zone_name zone name - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_GENERIC Unlocking failed. -*/ -API int vsm_unlock_zone(vsm_context_h ctx, const char *zone_name); - -/** - * @brief Switch target zone to foreground - * \par Description: - * Switch target zone to foreground on device. - * \param[in] zone vsm_zone_h - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_INVALID vsm_zone_h is invalid - */ -API int vsm_set_foreground(vsm_zone_h zone); - -/** - * @brief Get current foreground zone on device - * \par Description: - * Get foreground zone handle. - * \param[in] ctx vsm_context_h - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_INVALID vsm_context_h is invalid - */ -API vsm_zone_h vsm_get_foreground(vsm_context_h ctx); - -/// @} -/** - * @addtogroup ACCESS Vasum Access - * @{ -*/ - -/** - * @brief Definition for zone states. - * This definition shows the available states. -*/ -typedef enum { - VSM_ZONE_STATE_STOPPED, /**< Zone stopped */ - VSM_ZONE_STATE_STARTING, /**< Zone is prepare for running */ - VSM_ZONE_STATE_RUNNING, /**< Zone is running on device */ - VSM_ZONE_STATE_STOPPING, /**< Zone is stopping by request */ - VSM_ZONE_STATE_ABORTING, /**< Zone is failed to start */ - VSM_ZONE_STATE_FREEZING, /**< Reserved State */ - VSM_ZONE_STATE_FROZEN, /**< Reserved State */ - VSM_ZONE_STATE_THAWED, /**< Reserved State */ - VSM_ZONE_MAX_STATE = VSM_ZONE_STATE_THAWED -} vsm_zone_state_t; - - -/** - * @brief Definition for zone events -*/ -typedef enum { - VSM_ZONE_EVENT_NONE, /**< Zone has no event */ - VSM_ZONE_EVENT_CREATED, /**< Zone is created */ - VSM_ZONE_EVENT_DESTROYED, /**< Zone is destroted */ - VSM_ZONE_EVENT_SWITCHED, /**< Foreground is switched */ - VSM_ZONE_MAX_EVENT = VSM_ZONE_EVENT_SWITCHED -} vsm_zone_event_t; - - -/** - * @brief Definition for zone iteration callback function. - */ -typedef void (*vsm_zone_iter_cb)(vsm_zone_h zone, void *user_data); -/** - * @brief Definition for zone state changed callback function. - */ -typedef int (*vsm_zone_state_changed_cb)(vsm_zone_h zone, vsm_zone_state_t state, void *user_data); -/** - * @brief Definition for zone event callback function. - */ -typedef int (*vsm_zone_event_cb)(vsm_zone_h zone, vsm_zone_event_t event, void *user_data); - -/** - * @brief Interate all zone instances which are in running state - * \par Description: - * This API traverses all zones which are in running state, and callback function will be called on every entry. - * \param[in] ctx vsm context - * \param[in] callback Function to be executed in iteration, which can be NULL - * \param[in] user_data Parameter to be passed to callback function - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_OUT_OF_MEMORY Zone handle allocation failed - * \retval #VSM_ERROR_GENERIC Zone initialize failed - * \remark In case of callback and is NULL, - * This API refresh vsm_context which means reloading current running zone to vsm_context again. -*/ -API int vsm_iterate_zone(vsm_context_h ctx, vsm_zone_iter_cb callback, void *user_data); - -/** - * @brief Find zone corresponding to the name - * The function vsm_lookup_zone_by_name() looks for the zone instance corresponding to the given name. - * \param[in] ctx vsm context - * \param[in] name zone name - * \return Zone instance on success, or NULL on error. - * \retval vsm_zone_h Successful - * \retval NULL Failed to lookup - * \pre vsm_context_h have to bind by vsm_enter_eventloop() or vsm_context_h does not have current zone status. - * \see vsm_create_context(), vsm_enter_eventloop() -*/ -API vsm_zone_h vsm_lookup_zone_by_name(vsm_context_h ctx, const char *name); - -/** - * @brief Find zone instance associated with the process id - * \par Description: - * The function vsm_lookup_zone_by_pid() looks for the zone instance associated with the given pid. - * \param[in] ctx vsm context - * \param[in] pid Process id - * \return Zone instance on success, or NULL on error. - * \retval vsm_zone_h Successful - * \retval NULL Failed to lookup - * \pre vsm_context_h have to bind by vsm_enter_eventloop() or vsm_context_h does not have current zone status. - * \see vsm_create_context(), vsm_enter_eventloop() -*/ -API vsm_zone_h vsm_lookup_zone_by_pid(vsm_context_h ctx, pid_t pid); - -/** - * @brief Register zone status changed callback - * \par Description: - * Register a callback function for zone status change. - * \param[in] ctx vsm context - * \param[in] callback Callback function to invoke when zone satte event occurs - * \return Callback handle on success, or negative error code on error. - * \retval handle nonnegative handle id for callback. - * \retval #VSM_ERROR_OUT_OF_MEMORY Callback hanlder allocation failed. - * \pre vsm_context_h have to bind by vsm_enter_eventloop() or callback function does not called. - * \see vsm_create_context(), vsm_enter_eventloop(), vsm_del_state_changed_callback() -*/ -API int vsm_add_state_changed_callback(vsm_context_h ctx, vsm_zone_state_changed_cb callback, void *user_data); - -/** - * @brief Deregister zone status changed callback handler - * \par Description: - * Remove an event callback from the zone control context. - * \param[in] ctx vsm context - * \param[in] handle Callback Id to remove - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_NO_OBJECT Failed to lookup callback handler -*/ -API int vsm_del_state_changed_callback(vsm_context_h ctx, int handle); - -/** - * @brief Register zone event callback - * \par Description: - * Register a callback function for zone event. - * \param[in] ctx vsm context - * \param[in] callback callback function to invoke when zone event occurs - * \return positive callback handle on success, or negative error code on error. - * \retval handle nonnegative handle id for callback. - * \retval #VSM_ERROR_OUT_OF_MEMORY Callback hanlder allocation failed. - * \pre vsm_context_h have to bind by vsm_enter_eventloop() or callback function does not called. - * \see vsm_create_context(), vsm_enter_eventloop(), vsm_del_state_changed_callback() -*/ -API int vsm_add_event_callback(vsm_context_h ctx, vsm_zone_event_cb callback, void *user_data); - -/** - * @brief Deregister zone event callback handler - * \par Description: - * Remove an event callback from the zone control context. - * \param[in] ctx vsm context - * \param[in] handle callback handle to remove - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_NO_OBJECT Failed to lookup callback handler -*/ -API int vsm_del_event_callback(vsm_context_h ctx, int handle); - -/** - * @brief Zone attach parameters - * Arguments are same as linux system-call execv() - */ -typedef struct vsm_attach_command_s { - char * exec; /**< Program binary path */ - char ** argv; /**< An array of argument pointers to null-terminated strings include program path */ -} vsm_attach_command_s; - -/** - * @brief Zone attach option - */ -typedef struct vsm_attach_options_s { - uid_t uid; /**< requested uid*/ - gid_t gid; /**< requested gid*/ - int env_num; /**< requested environ count */ - char **extra_env; /**< requested environ string pointer array. */ -} vsm_attach_options_s; - -/** - * @brief default attach options - * \n - * uid = root\n - * gid = root\n - * env = no extra env\n - */ - -#define VSM_ATTACH_OPT_DEFAULT { (uid_t)0, (gid_t)0, 0, NULL } - -/** - * @brief Launch a process in a running zone. - * \par Description: - * Execute specific command inside the zone with given arguments and environment - * \param[in] zone_name vsm_zone_h - * \param[in] command vsm attach command - * \param[in] opt vsm attach options (can be NULL), using VSM_ATTACH_OPT_DEFAULT - * \param[out] attached_process process pid - * \return On sucess 0, otherwise, a negative integer error code on error - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_INVALID Invalid arguments - * \retval #VSM_ERROR_NO_OBJECT Target zone is not running state - * \retval #VSM_ERROR_GENERIC IPC failed - */ -API int vsm_attach_zone(vsm_context_h ctx, const char * zone_name, vsm_attach_command_s * command, vsm_attach_options_s * opt, pid_t *attached_process); - -/** - * @brief Launch a process in a running zone and wait till child process exited. - * \par Description: - * Execute specific command inside the zone with given arguments and environment - * \param[in] zone_name vsm_zone_h - * \param[in] command vsm attach command - * \param[in] opt vsm attach options (can be NULL), using VSM_ATTACH_OPT_DEFAULT - * \return On sucess waitpid exit code or attached process, or a negative error code - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_INVALID Invalid arguments - * \retval #VSM_ERROR_NO_OBJECT Target zone is not running state - * \retval #VSM_ERROR_GENERIC IPC failed or waitpid error - */ -API int vsm_attach_zone_wait(vsm_context_h ctx, const char * zone_name, vsm_attach_command_s * command, vsm_attach_options_s * opt); - -/** - * @brief Get name string of zone. - * \par Description: - * Get name string of zone. - * \param[in] zone vsm zone handle - * \return a pointer of zone name string on sucess or NULL on fail. - * \retval name string value of zone. - * \retval NULL vsm_zone_h is invalid. - * \warning Do not modify or free returned pointer memroy. - * This memory will be cleanup by vsm_cleanup context() -*/ -API const char * vsm_get_zone_name(vsm_zone_h zone); - -/** - * @brief Get zone root ablsolute path on host side. - * \par Description: - * Get rootpath string of zone. - * \param[in] zone vsm zone handle - * \return a pointer of zone rootpath string on sucess or NULL on fail. - * \retval rootpath string value of zone. - * \retval NULL vsm_zone_h is invalid. - * \warning Do not modify or free returned memroy. - * This memory will be cleanup by vsm_cleanup context() -*/ -API const char * vsm_get_zone_rootpath(vsm_zone_h zone); - -/** - * @brief Get type of running zone. - * \par Description: - * Get type string of zone. This value is defined in template file when using vsm_create_zone() - * \param[in] zone vsm zone handle - * \return a pointer of zone path string on sucess or NULL on fail. - * \retval rootpath string value of zone. - * \retval NULL vsm_zone_h is invalid. - * \see vsm_create_zone() - * \warning Do not modify or free returned memroy. - * This memory will be cleanup by vsm_cleanup context() -*/ -API const char * vsm_get_zone_type(vsm_zone_h zone); - -/** - * @brief Check zone handle, a host or a normal zone by zone handle. - * \param[in] zone vsm zone handle - * \return positive integer on host case, or 0 on normal zone. - * \retval positive target zone is host zone. - * \retval NULL target zone is NOT host. -*/ -API int vsm_is_host_zone(vsm_zone_h zone); - -/** - * @brief get zone state. - * \par Description: - * Get zone state value by zone handle. - * \param[in] zone vsm zone handle - * \return vsm_zone_state_t value, or negative value. - * \retval state vsm_zone_state_t value of zone - * \retval #VSM_ERROR_INVALID vsm_zone_h is invalid -*/ - -API vsm_zone_state_t vsm_get_zone_state(vsm_zone_h zone); - -/** - * @brief get zone id by handle. - * \par Description: - * Get zone id value by zone handle. - * \param[in] zone vsm zone handle - * \return interger id value of zone or negative error. - * \retval id nonnegative interger value. - * \retval #VSM_ERROR_INVALID vsm_zone_h is invalid - * \remarks id '0' is reserved for host. -*/ -API int vsm_get_zone_id(vsm_zone_h zone); - -/** - * @brief Set userdata pointer value in vsm_zone_h. - * \par Description: - * Get zone id value by zone handle. - * \param[in] zone vsm zone handle - * \return On success 0, or negative error. - * \retval #VSM_ERROR_NONE Successful. - * \retval #VSM_ERROR_INVALID vsm_zone_h is invalid - * \warning This userdata have to be free before vsm_cleanup_context() or VSM_ZONE_STATE_STOPPED callback handler -*/ -API int vsm_set_userdata(vsm_zone_h zone, void * userdata); - -/** - * @brief Set userdata pointer value in vsm_zone_h. - * \par Description: - * Get zone id value by zone handle. - * \param[in] zone vsm zone handle - * \return On success pointer of userdata, or NULL pointer - * \retval userdata pointer of userdata. - * \retval NULL invalid vsm_zone_h. - * \remark initial value is pointer of self vsm_zone_h -*/ -API void * vsm_get_userdata(vsm_zone_h zone); - - -/** - * @brief join current process into zone. - * \par Synopsys: - * Change self peer credential to target zone - * \param[in] zone vsm_zone_h - * \return before vsm_zone on success, or NULL on error. - * \retval vsm_zone_h before zone handle, If caller process running in host, then host handle returned. - * \retval NULL invalid zone handle. - * \pre parameter vsm zone must be lookup by vsm lookup APIs - * \post After finish target zone procedure, must join again before zone by same API. - * \warning This function is not thread-safe. \n - * All requests of threads in same process are considered target zone request to other host processes. - */ -API vsm_zone_h vsm_join_zone(vsm_zone_h zone); - -/** - * @brief get canonical file path based on current zone. - * \par Description: - * get canonical file path based on current zone. - * \param[in] input_path requested zone path - * \param[out] output_path string pointer for canonicalized output path - * \return int positive string length of output_path, or negative error code on error. - * \retval #VSM_ERROR_INVALID Invalid arguments. - * \retval #VSM_ERROR_GENERIC gethostname() is failed. - * \post Out buffer(*output_path) have to be freed by caller after use. - * \remarks This API can call inside zone without vsm_context_h - * It means this API can call library side for apps. - */ -API int vsm_canonicalize_path(const char *input_path, char **output_path); - -/** - * @brief Check current environment, a host or virtualized zone. - * \par Description: - * Check current caller process environment. - * \return positive integer on running in zone, or 0 on running in host. - * \retval NULL Current process running in host. - * \remarks This API can call inside zone without vsm_context_h - * It means this API can call library side for apps. - */ -API int vsm_is_virtualized(void); - -/** - * @brief Check equivalence between caller and target pid. - * \par Description: - * Check API caller process and target pid running in same zone. - * \retval NULL target process is running in another zone. - * \retval 1 target process is running in same zone. - * \retval -1 failed to check target process. - * \remarks This API can check real zone of target pid. - Real zone is not changed by even join API. - */ -API int vsm_is_equivalent_zone(vsm_context_h ctx, pid_t pid); - -/** - * @brief Translate zone pid to host pid. - * \par Description: - * This API would translate zone namespace pid to host namespace pid. - * \param[in] zone the zone of target process - * \param[in] pid target process id of zone namespace - * \return positive pid or negative error code. - * \retval pid translated host pid of zone process. - * \retval #VSM_ERROR_NO_OBJECT No such process in a target zone. - * \retval #VSM_ERROR_NOT_PERMITTED Permission denied to get target pid info. - * \retval #VSM_ERROR_NOT_SUPPORTED Kernel config is not enabled about pid namespace. - * \retval #VSM_ERROR_INVALID Arguments is invalid. - * \retval #VSM_ERROR_IO Failed to get process info. - * \retval #VSM_ERROR_GENERIC Failed to matching zone pid to host pid. - */ -API int vsm_get_host_pid(vsm_zone_h zone, pid_t pid); - - -/// @} - -/** - * @addtogroup NETWORK Vasum Network - * @{ -*/ - -/** - * @brief Types of virtual network interfaces - */ -typedef enum { - VSM_NETDEV_VETH, /**< Virtual Ethernet(veth), this type device will be attached to host-side network bridge */ - VSM_NETDEV_PHYS, /**< Physical device */ - VSM_NETDEV_MACVLAN /**< Mac VLAN, this type isn't implemented yet */ -} vsm_netdev_type_t; - -typedef enum { - VSM_NETDEV_ADDR_IPV4, /**< IPV4 Address family */ - VSM_NETDEV_ADDR_IPV6 /**< IPV6 Address family */ -} vsm_netdev_addr_t; - -/** - * @brief Network device information - */ -typedef struct vsm_netdev *vsm_netdev_h; - -/** - * @brief Definition for zone network devince iteration callback function. - */ -typedef void (*vsm_zone_netdev_iter)(struct vsm_netdev *, void *user_data); - -/** - * @brief Create a new network device and assisgn it to zone - * \par Description: - * This function creates net netdev instance and assign it to the given zone. - * \param[in] zone Zone - * \param[in] type Type of network device to be create - * \param[in] target - * - If type is veth, this will be bridge name to attach. - * - If type is phys, this will be ignored. - * \param[in] netdev Name of network device to be create - * \return Network devce on success, or NULL on error. - * \retval vsm_netdev_h New net device handle - * \retval NULL Failed to create netdev - * \see vsm_create_netdev() - * \par Known Issues: - * Macvlan is not implemented yet. - */ -API vsm_netdev_h vsm_create_netdev(vsm_zone_h zone, vsm_netdev_type_t type, const char *target, const char *netdev); - -/** - * @brief Removes a network device from zone - * \par Description: - * This function remove the given netdev instance from the zone control context. - * \param[in] netdev network device to be removed - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_INVALID Invalid arguments - * \retval #VSM_ERROR_GENERIC Failed to interact with vasum server - * \see vsm_destroy_netdev() - */ -API int vsm_destroy_netdev(vsm_netdev_h netdev); - -/** - * @brief Iterates network devices found in the zone vsm context and executes callback() on each interface. - * \par Description: - * vsm_destroy_netdev() scans all network interfaces which are registered in the vsm context, and calls callback() on each entry. - * \param[in] zone Zone - * \param[in] callback Function to be executed in iteration, which can be NULL - * \param[in] user_data Parameter to be delivered to callback function - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_INVALID Invalid arguments - * \retval #VSM_ERROR_GENERIC Failed to interact with vasum server - * \see vsm_create_netdev(), vsm_destroy_netdev() - */ -API int vsm_iterate_netdev(vsm_zone_h zone, vsm_zone_netdev_iter callback, void *user_data); - -/** - * @brief Find a network device corresponding to the name - * \par Description: - * The function vsm_lookup_netdev_by_name() looks for a network interface. - * \param[in] name Network device name to search - * \return Network device on success, or NULL on error. - * \retval vsm_netdev_h Target net device handle - * \retval NULL Failed to lookup netdev - */ - -API vsm_netdev_h vsm_lookup_netdev_by_name(vsm_zone_h zone, const char *name); - -/** - * @brief Turn up a network device in the zone - * \par Description: - * This function turns up the given netdev instance in the zone. - * \param[in] netdev network device to be removed - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_INVALID Invalid arguments - * \retval #VSM_ERROR_GENERIC Failed to interact with vasum server - * \see vsm_down_netdev() - */ -API int vsm_up_netdev(vsm_netdev_h netdev); - -/** - * @brief Turn down a network device in the zone - * \par Description: - * This function turns down the given netdev instance in the zone. - * \param[in] netdev network device to be removed - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_INVALID Invalid arguments - * \retval #VSM_ERROR_GENERIC Failed to interact with vasum server - * \see vsm_down_netdev() - */ -API int vsm_down_netdev(vsm_netdev_h netdev); - -/** - * @brief Get ip address from a network device - * \par Description: - * The function vsm_get_ip_addr_netdev() get ip address from a network interface - * \param[in] netdev Network device to get address - * \param[in] addr_family Address family - * \param[out] addr Buffer to get address from a network device - * \param[out] size Size of buffer - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_INVALID Invalid arguments - * \retval #VSM_ERROR_OVERFLOW Parameter overflow - * \retval #VSM_ERROR_GENERIC Failed to interact with vasum server - * \see vsm_set_ip_addr_netdev() - */ -API int vsm_get_ip_addr_netdev(vsm_netdev_h netdev, vsm_netdev_addr_t addr_family, char *addr, int size); - -/** - * @brief Set ip address to a network device - * \par Description: - * The function vsm_set_ip_addr_netdev() set ipv4 address to a network interface - * \param[in] netdev Network device to set address - * \param[in] addr_family Address family - * \param[in] addr IP address string to be set - * \param[in] prefix prefix ( ex> 192.168.122.1/24, 24 is prefix ) - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_INVALID Invalid arguments - * \retval #VSM_ERROR_OVERFLOW Parameter overflow - * \retval #VSM_ERROR_GENERIC Failed to interact with vasum server - * \see vsm_get_ip_addr_netdev() - */ -API int vsm_set_ip_addr_netdev(vsm_netdev_h netdev, vsm_netdev_addr_t addr_family, const char *addr, int prefix); - - - -/// @} - -/** - * @addtogroup DEVICE Vasum Device - * @{ -*/ - -/** - * @brief Grant device to zone - * \par Description: - * Request permission device file node to target zone. - * \param[in] zone vsm_zone_h - * \param[in] path device node path - * \param[in] flags requested permission O_RDWR, O_WRONLY, O_RDONLY - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_INVALID Invalid arguments - * \retval #VSM_ERROR_NOT_PERMITTED Change cgroup is not permitted - * \retval #VSM_ERROR_GENERIC Failed to interact with vasum server - * \see vsm_revoke_device() - */ -API int vsm_grant_device(vsm_zone_h zone, const char *path, uint32_t flags); - -/** - * @brief Revoke device from the zone - * \par Description: - * Revoke device node permissions from target zone. - * \param[in] zone vsm_zone_h - * \param[in] path device node path - * \return 0 on success, or negative integer error code on error. - * \retval #VSM_ERROR_NONE Successful - * \retval #VSM_ERROR_INVALID Invalid arguments - * \retval #VSM_ERROR_NOT_PERMITTED Change cgroup is not permitted - * \retval #VSM_ERROR_GENERIC Failed to interact with vasum server - * \see vsm_grant_device() - */ -API int vsm_revoke_device(vsm_zone_h zone, const char *path); -/// @} - - -/** - * @addtogroup RESOURCE Vasum Resource - * @{ - */ - -/** - * @brief Definition for declare file type. -*/ -typedef enum { - VSM_FSO_TYPE_DIR, /**< Directoy type */ - VSM_FSO_TYPE_REG, /**< Regular file type */ - VSM_FSO_TYPE_FIFO, /**< Fifo file type */ - VSM_FSO_TYPE_SOCK, /**< Socket file type */ - VSM_FSO_TYPE_DEV, /**< Device node type */ - VSM_FSO_MAX_TYPE = VSM_FSO_TYPE_DEV -} vsm_fso_type_t; - - -/** - * @brief Declare file mode. -*/ -typedef mode_t vsm_mode_t; - -/** - * @brief Declare specific file object to every zone. - * \par Description: - * Declare host file system to every running zone. - * In case of host target file exist, create new file in running zone. or create a new file in running zone. - * And add hook info in vsm-resource-provier for automatically link host target file to starting zone. - * Smack labels are also copied as same as host labels. - * \param[in] ctx vsm context - * \param[in] ftype Type of file system object - * \param[in] path Path for the file system object - * \param[in] flags Flasg - * \param[in] mode mode - * \return zero on success, or negative value on error. - * \retval #VSM_ERROR_NONE successful. - * \retval #VSM_ERROR_INVALID Invalid file type or path. - * \retval #VSM_ERROR_GENERIC Error in vasum server side. - * \retval #VSM_ERROR_NO_OBJECT Source file is not exist in host filesystem -*/ -API int vsm_declare_file(vsm_context_h ctx, vsm_fso_type_t ftype, const char *path, int flags, vsm_mode_t mode); - -/** - * @brief Declare hardlink to every zone. - * \par Description: - * Declare hardlink to host file to every running zone. - * And add hook info in vsm-resource-provier for automatically link host target file to starting zone. - * In general, this function is used to share file host and all running zones. - * Smack labels are also copied as same as host labels. - * \param[in] ctx vsm context - * \param[in] source source - * \param[in] target target - * \return zero on success, or negative value on error. - * \retval #VSM_ERROR_NONE successful - * \retval #VSM_ERROR_INVALID Invalid provision type to db. - * \retval #VSM_ERROR_GENERIC Error in vasum server side. - * \retval #VSM_ERROR_NO_OBJECT Source file is not exist in host filesystem -*/ -API int vsm_declare_link(vsm_context_h ctx , const char *source, const char *target); -/// @} - - -/* - Below datatypes will be opaque. -*/ -typedef struct vsm_context { - void * signal_channel; - void * manage_method_channel; - void * unpriv_method_channel; - vsm_error_e error; - pthread_rwlock_t lock; - struct adt_list listeners; - struct vsm_zone *root_zone; - struct vsm_zone *foreground_zone; - struct adt_list sc_listeners; - struct adt_list ev_listeners; - void * vsm_ops; -} vsm_context_s; - -typedef struct vsm_zone { - struct vsm_zone *parent; - char *name; - char *type; - int terminal; - vsm_zone_state_t state; - char *rootfs_path; - pthread_rwlock_t lock; - struct adt_list children; - struct adt_list devices; - struct adt_list netdevs; - void *user_data; - struct adt_list list; - struct vsm_context *ctx; - int id; -} vsm_zone_s; - -typedef struct vsm_netdev { - struct vsm_zone *zone; - char *name; - vsm_netdev_type_t type; - struct adt_list list; -} vsm_netdev_s; - -/* - Below APIs will be removed. -*/ - -typedef int (*vsm_zone_state_cb)(vsm_zone_h zone, vsm_zone_state_t state ,vsm_zone_event_t event, void *user_data); - -API int vsm_add_state_callback(vsm_context_h ctx, vsm_zone_state_cb callback, void *user_data); - -API int vsm_del_state_callback(vsm_context_h ctx, int handle); - -API int vsm_get_zone_terminal(vsm_zone_h zone); - -#ifdef __cplusplus -} -#endif - -#endif /*! __VASUM_H__ */ diff --git a/wrapper/vasum.pc.in b/wrapper/vasum.pc.in deleted file mode 100644 index 2f2247b..0000000 --- a/wrapper/vasum.pc.in +++ /dev/null @@ -1,12 +0,0 @@ -# Package Information for pkg-config - -prefix=@CMAKE_INSTALL_PREFIX@ -exec_prefix=${prefix} -libdir=@LIB_INSTALL_DIR@ -includedir=${prefix}/include - -Name: vasum -Description: Vasum library -Version: @_LIB_VERSION_@ -Libs: -L${libdir} -lvasum -Cflags: -I${includedir}/vasum diff --git a/wrapper/vasum_list.h b/wrapper/vasum_list.h deleted file mode 100644 index 5e9c82e..0000000 --- a/wrapper/vasum_list.h +++ /dev/null @@ -1,102 +0,0 @@ -#ifndef __VASUM_ADT_LIST_H__ -#define __VASUM_ADT_LIST_H__ - -struct adt_list { - struct adt_list* next; - struct adt_list* prev; -}; - -#undef offsetof -#ifdef __compiler_offsetof -#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) -#else -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) -#endif - -#define container_of(ptr, type, member) ({ \ - const typeof( ((type *)0)->member ) *__mptr = (ptr); \ - (type *)( (char *)__mptr - offsetof(type,member) );}) - -#define adt_iterate_list(__iterator, __list) \ - for (__iterator = (__list)->next; \ - __iterator != __list; \ - __iterator = (__iterator)->next) - -#define adt_reverse_iterate_list(__iterator, __list) \ - for (__iterator = __list; \ - (__iterator)->next != __list; \ - __iterator = (__iterator)->next); \ - for ( ; \ - __iterator != __list; \ - __iterator = (__iterator)->prev) - -#define ADT_INIT_LIST(name) { &(name), &(name) } - -static inline void adt_init_list(struct adt_list* list) -{ - list->next = list->prev = list; -} - -static inline int adt_empty_list(struct adt_list* list) -{ - return (list == list->next) && (list == list->prev); -} - -static inline void __adt_list_add(struct adt_list* _new, - struct adt_list* prev, - struct adt_list* next) -{ - next->prev = _new; - _new->next = next; - _new->prev = prev; - prev->next = _new; -} - -static inline void adt_link_list(struct adt_list* head, struct adt_list* list) -{ - __adt_list_add(list, head, head->next); -} - -static inline void adt_unlink_list(struct adt_list* list) -{ - struct adt_list* next, *prev; - - next = list->next; - prev = list->prev; - next->prev = prev; - prev->next = next; -} - -static inline void adt_sort_list(struct adt_list* head, - int (*compare_func)(struct adt_list *, struct adt_list *)) -{ - struct adt_list *it, *jt, *kt; - - if (adt_empty_list(head)) - return; - - for (it = head->next->next; it != head; it = it->next) { - for (jt = head->next; jt != it; jt = jt->next) { - if (compare_func(it, jt) < 0) { - kt = it; - it = it->prev; - adt_unlink_list(kt); - adt_link_list(jt->prev, kt); - break; - } - } - } -} - -static inline struct adt_list *adt_find_list(struct adt_list* head, - int (*equal_func)(struct adt_list *, void *), void *value) -{ - struct adt_list *it; - adt_iterate_list(it, head) { - if (equal_func(it, value)) - return it; - } - return NULL; -} - -#endif /*!__VASUM_ADT_LIST_H__*/ diff --git a/wrapper/wrapper-compatibility.cpp b/wrapper/wrapper-compatibility.cpp deleted file mode 100644 index 04c043d..0000000 --- a/wrapper/wrapper-compatibility.cpp +++ /dev/null @@ -1,1671 +0,0 @@ -/* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved - * - * Contact: Krzysztof Dynowski - * - * 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 Krzysztof Dynowski (k.dynowski@samsung.com) - * @brief Vasum old API compatibility functions - */ - -#include "wrapper-compatibility.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include //PRIx64 -#include -#include -#include -#include -#include -#include -#include -#include - -#include "logger/logger.hpp" -#include "logger/logger-scope.hpp" - -#define UNUSED(x) ((void)(x)) - -extern "C" { - -// find_container_by_pid -API char *find_container_by_pid(pid_t /*pid*/) { - LOGS(""); - return NULL; -} -// get_domain_pid -API pid_t get_domain_pid(const char * /*name*/, const char * /*target*/) { - LOGS(""); - return -1; -} - -// sock_close_socket -API int sock_close_socket(int fd) { - LOGS(""); - struct sockaddr_un addr; - socklen_t addrlen = sizeof(addr); - - if (!getsockname(fd, (struct sockaddr *)&addr, &addrlen) && addr.sun_path[0]) { - unlink(addr.sun_path); - } - - close(fd); - - return 0; -} -// sock_connect -API int sock_connect(const char *path) { - LOGS(""); - size_t len; - int fd, idx = 0; - struct sockaddr_un addr; - - fd = socket(PF_UNIX, SOCK_STREAM, 0); - if (fd < 0) { - return -1; - } - - memset(&addr, 0, sizeof(addr)); - - addr.sun_family = AF_UNIX; - - /* Is it abstract address */ - if (path[0] == '\0') { - idx++; - } - LOGD("socket path=" << &path[idx]); - len = strlen(&path[idx]) + idx; - if (len >= sizeof(addr.sun_path)) { - close(fd); - errno = ENAMETOOLONG; - return -1; - } - - strncpy(&addr.sun_path[idx], &path[idx], strlen(&path[idx])); - if (connect - (fd, (struct sockaddr *)&addr, - offsetof(struct sockaddr_un, sun_path) + len)) { - close(fd); - return -1; - } - - return fd; -} - -// sock_create_socket -API int sock_create_socket(const char *path, int type, int flags) { - LOGS(""); - size_t len; - int fd, idx = 0; - struct sockaddr_un addr; - - if (!path) - return -1; - - if (flags & O_TRUNC) - unlink(path); - - fd = socket(PF_UNIX, type, 0); - if (fd < 0) { - return -1; - } - - memset(&addr, 0, sizeof(addr)); - - addr.sun_family = AF_UNIX; - - /* Is it abstract address */ - if (path[0] == '\0') { - idx++; - } - LOGD("socket path=" << &path[idx]); - len = strlen(&path[idx]) + idx; - if (len >= sizeof(addr.sun_path)) { - close(fd); - errno = ENAMETOOLONG; - return -1; - } - - strncpy(&addr.sun_path[idx], &path[idx], strlen(&path[idx])); - - if (bind (fd, (struct sockaddr *)&addr, offsetof(struct sockaddr_un, sun_path) + len)) { - close(fd); - return -1; - } - - if (type == SOCK_STREAM && listen(fd, 100)) { - close(fd); - return -1; - } - - return fd; -} - -// "Fowler–Noll–Vo hash function" implementation (taken from old API source) -#define FNV1A_64_INIT ((uint64_t)0xcbf29ce484222325ULL) -static uint64_t hash_fnv_64a(void *buf, size_t len, uint64_t hval) -{ - unsigned char *bp; - - for (bp = (unsigned char *)buf; bp < (unsigned char *)buf + len; bp++) { - hval ^= (uint64_t) * bp; - hval += (hval << 1) + (hval << 4) + (hval << 5) + - (hval << 7) + (hval << 8) + (hval << 40); - } - - return hval; -} - -// sock_monitor_address -API int sock_monitor_address(char *buffer, int len, const char *lxcpath) { - LOGS(""); - int ret; - uint64_t hash; - char *sockname; - char path[PATH_MAX]; - - memset(buffer, 0, len); - sockname = &buffer[1]; - - ret = snprintf(path, sizeof(path), "lxc/%s/monitor-sock", lxcpath); - if (ret < 0) { - errno = ENAMETOOLONG; - return -1; - } - - hash = hash_fnv_64a(path, ret, FNV1A_64_INIT); - ret = snprintf(sockname, len, "lxc/%016" PRIx64 "/%s", hash, lxcpath); - if (ret < 0) { - errno = ENAMETOOLONG; - return -1; - } - - return 0; -} -// sock_recv_fd (intern) -API int sock_recv_fd(int fd, int *recvfd, void *data, size_t size) { - LOGS(""); - struct msghdr msg; - struct iovec iov; - int ret; - union { - struct cmsghdr cm; - char control[CMSG_SPACE(sizeof(int))]; - } control_un; - struct cmsghdr *cmsg; - char dummy=1; - - memset(&msg, 0, sizeof(msg)); - msg.msg_name = NULL; - msg.msg_namelen = 0; - - msg.msg_control = control_un.control; - msg.msg_controllen = sizeof(control_un.control); - - iov.iov_base = data ? data : &dummy; - iov.iov_len = data ? size : sizeof(dummy); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - ret = recvmsg(fd, &msg, 0); - if (ret <= 0) - return ret; - - cmsg = CMSG_FIRSTHDR(&msg); - if (cmsg && cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && - cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - *recvfd = *((int *)CMSG_DATA(cmsg)); - } - else - *recvfd = -1; - - return ret; -} -// sock_send_fd -API int sock_send_fd(int fd, int sendfd, void *data, size_t size) { - LOGS(""); - struct msghdr msg; - struct iovec iov; - union { - struct cmsghdr cm; - char control[CMSG_SPACE(sizeof(int))]; - } control_un; - struct cmsghdr *cmsg; - char dummy=1; - - memset(&msg, 0, sizeof(msg)); - msg.msg_control = control_un.control; - msg.msg_controllen = sizeof(control_un.control); - - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - *((int *)CMSG_DATA(cmsg)) = sendfd; - - msg.msg_name = NULL; - msg.msg_namelen = 0; - - iov.iov_base = data ? data : &dummy; - iov.iov_len = data ? size : sizeof(dummy); - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - - return sendmsg(fd, &msg, MSG_NOSIGNAL); -} -// vasum_log -API void vasum_log(__attribute__((unused)) int type, - __attribute__((unused)) const char *tag, - const char *fmt, ...) { - va_list arg_ptr; - char buf[255]; - LOGS("type=" << type << " tag=" << tag); - va_start(arg_ptr, fmt); - vsnprintf(buf, sizeof(buf), fmt, arg_ptr); - va_end(arg_ptr); - buf[sizeof(buf)-1]=0; - LOGD("msg=" << buf); -} - -#define MAX_ERROR_MSG 0x1000 -#define BUF_SIZE 4096 - -#define SMACK_LABEL_LEN 8 -#define ERROR(...) do{}while(0) -#define WARN(...) do{}while(0) -#define DEBUG(...) do{}while(0) -#define INFO(...) do{}while(0) - -// lib/utils.c -const char *const fso_type_strtab[] = { - "Directory", - "Regular file", - "FIFO", - "Socket", - "Device node" -}; - -API const char *fso_type_to_string(vsm_fso_type_t fso) -{ - LOGS(""); - if (fso < 0 || fso > VSM_FSO_MAX_TYPE) { - return NULL; - } - - return fso_type_strtab[fso]; -} - -API int wait_for_pid_status(pid_t pid) -{ - LOGS(""); - int status, ret; - - again: - ret = waitpid(pid, &status, 0); - if (ret == -1) { - if (errno == EINTR) { - goto again; - } else { - ERROR("waitpid pid : %d error : %s", pid, strerror(errno)); - return -1; - } - } - if (ret != pid) - goto again; - return status; -} - -API vsm_fso_type_t fso_string_to_type(char *str) -{ - LOGS(""); - int i; - for (i = 0; i <= VSM_FSO_MAX_TYPE; i++) { - int len = strlen(fso_type_strtab[i]); - if (strncmp(str, fso_type_strtab[i], len) == 0) - return static_cast(i); - } - - return static_cast(-1); -} - -API int mkdir_p(const char *dir, mode_t mode) -{ - LOGS(""); - const char *tmp = dir; - const char *orig = dir; - - do { - dir = tmp + strspn(tmp, "/"); - tmp = dir + strcspn(dir, "/"); - char *makeme = strndup(orig, dir - orig); - if (*makeme) { - if (mkdir(makeme, mode) && errno != EEXIST) { - free(makeme); - return -1; - } - } - free(makeme); - } while (tmp != dir); - - return 0; -} - -API int lock_fd(int fd, int wait) -{ - LOGS(""); - int ret; - struct flock f; - - while (1) { - f.l_type = F_WRLCK; - f.l_whence = SEEK_SET; - f.l_start = 0; - f.l_len = 0; - - if (wait) - ret = fcntl(fd, F_SETLKW, &f); - else - ret = fcntl(fd, F_SETLK, &f); - if (ret != -1) - return 0; - if (errno == EINTR) - continue; - return -1; - } -} - -API int unlock_fd(int fd) -{ - LOGS(""); - struct flock f; - f.l_type = F_UNLCK; - f.l_whence = SEEK_SET; - f.l_start = 0; - f.l_len = 0; - return fcntl(fd, F_SETLKW, &f); -} - -API int copy_smacklabel(const char * /*source*/, const char * /*dest*/) -{ - LOGS(""); - return 0; -} - -API int remove_file(char *path) -{ - LOGS(""); - struct stat path_stat; - int status = 0; - - if (lstat(path, &path_stat) < 0) { - if (errno != ENOENT) { - ERROR("Unable to stat : %s"); - return -1; - } - } - - if (S_ISDIR(path_stat.st_mode)) { - struct dirent *d; - DIR *dp; - if ((dp = opendir(path)) == NULL) { - ERROR("Unable to opendir %s", path); - return -1; - } - - while ((d = readdir(dp)) != NULL) { - char new_path[PATH_MAX]; - if (strcmp(d->d_name, ".") == 0 || - strcmp(d->d_name, "..") == 0) - continue; - - snprintf(new_path, PATH_MAX, "%s/%s", path, d->d_name); - if (remove_file(new_path) < 0) - status = -1; - } - - if (closedir(dp) < 0) { - ERROR("Unable to close dp : %s", path); - return -1; - } - - if (rmdir(path) < 0) { - ERROR("Failed to remove dir : %s, cause: %s", path, - strerror(errno)); - return -1; - } - - } else { - if (unlink(path) < 0) { - ERROR("Unable to remove %s", path); - return -1; - } - } - - return status; -} - -API int copy_file(const char *source, const char *dest, int /*flags*/) -{ - LOGS(""); - int ret; - FILE *sfp, *dfp; - char buffer[BUF_SIZE]; - - if ((sfp = fopen(source, "r")) == NULL) { - ERROR("Unable to open source : %s", source); - return -1; - } - - if ((dfp = fopen(dest, "w+")) == NULL) { - ERROR("Unable to open destination : %s", dest); - fclose(sfp); - return -1; - } - - while (1) { - size_t nread, nwritten, size = BUF_SIZE; - nread = fread(buffer, 1, size, sfp); - - if (nread != size && ferror(sfp)) { - ERROR("Read failed"); - return -1; - } else if (nread == 0) { - break; - } - - nwritten = fwrite(buffer, 1, nread, dfp); - - if (nwritten != nread) { - if (ferror(dfp)) - ERROR("write fail"); - else - ERROR("Unable to write all data"); - return -1; - } - } - - fclose(sfp); - fclose(dfp); - - ret = copy_smacklabel(source, dest); - if (ret != 0) { - ERROR("Unable to setting smack lable"); - return -1; - } - return 0; -} - -API int regex_compile(regex_t * r, const char *regex_text) -{ - LOGS(""); - int status = regcomp(r, regex_text, REG_EXTENDED | REG_NEWLINE); - - if (status != 0) { - char error_message[MAX_ERROR_MSG]; - - regerror(status, r, error_message, MAX_ERROR_MSG); - DEBUG("Regex error compiling '%s': %s\n", - regex_text, error_message); - return 1; - } - - return 0; -} - -API int regex_match(regex_t * r, const char *to_match) -{ - LOGS(""); - const char *p = to_match; - const int n_matches = 10; - regmatch_t m[n_matches]; - - while (1) { - int i = 0; - int nomatch = regexec(r, p, n_matches, m, 0); - - if (nomatch) { - DEBUG("No more matches.\n"); - return nomatch; - } - - for (i = 0; i < n_matches; i++) { - int start; - int finish; - UNUSED(start); - UNUSED(finish); - - if (m[i].rm_so == -1) { - break; - } - - start = m[i].rm_so + (p - to_match); - finish = m[i].rm_eo + (p - to_match); - if (i == 0) { - INFO("$& is "); - } else { - INFO("$%d is ", i); - } - - INFO("'%.*s' (bytes %d:%d)\n", (finish - start), - to_match + start, start, finish); - } - - p += m[0].rm_eo; - } - - return 0; -} - -API int get_peer_pid(int fd) -{ - LOGS(""); - struct ucred cred; - socklen_t cr_len = sizeof(cred); - if (getsockopt(fd, SOL_SOCKET, SO_PEERCRED, &cred, &cr_len) < 0) { - return -1; - } - return cred.pid; -} - -API pid_t gettid(void) -{ - LOGS(""); - return syscall(__NR_gettid); -} - -API int set_smacklabel_fd(int fd, const char *xattr_name, const char *label) -{ - LOGS(""); - size_t len; - int ret; - - if (fd < 0) - return -1; - - len = strnlen(label, SMACK_LABEL_LEN + 1); - if (len > SMACK_LABEL_LEN) - return -1; - - ret = fsetxattr(fd, xattr_name, label, len + 1, 0); - if (ret != 0) { - ERROR("Set Smack lable error : %s", strerror(errno)); - } - return ret; -} - -API int set_smacklabel(const char *path, const char *xattr_name, const char *label) -{ - LOGS(""); - size_t len; - int ret; - - if (path == NULL) - return -1; - - len = strnlen(label, SMACK_LABEL_LEN + 1); - if (len > SMACK_LABEL_LEN) - return -1; - - ret = lsetxattr(path, xattr_name, label, len + 1, 0); - if (ret != 0) { - ERROR("Set Smack lable error : %s", strerror(errno)); - } - return ret; -} -API char *get_self_smacklabel(void) -{ - LOGS(""); - int ret; - int fd; - const char *attr_path = "/proc/self/attr/current"; - char buffer[SMACK_LABEL_LEN + 1]; - - bzero(buffer, SMACK_LABEL_LEN + 1); - - fd = open(attr_path, O_RDONLY); - if (fd < 0) { - return NULL; - } - - ret = read(fd, buffer, SMACK_LABEL_LEN + 1); - close(fd); - if (ret < 0) { - return NULL; - } - - if (ret > SMACK_LABEL_LEN) { - //return NULL; - } - buffer[SMACK_LABEL_LEN] = 0; - - return strdup(buffer); -} - -API int get_self_cpuset(char *name, int buf_sz) -{ - LOGS(""); - int fd; - int lxc_len, ret; - char cpuset_path[] = "/proc/self/cpuset"; - char current_name[NAME_MAX]; - - fd = open(cpuset_path, O_RDONLY); - if (fd < 0) { - return 0; - } - - ret = read(fd, current_name, NAME_MAX - 1); - if (ret < 0) { - close(fd); - return -1; - } - - current_name[ret - 1] = '\0'; - close(fd); - - lxc_len = sizeof("/lxc"); - if (ret < lxc_len) { - name[0] = '/'; - name[1] = 0; - return 1; - } else { - char *p; - p = current_name + lxc_len; - - while (*p != '\0') { - if (*p == '/') { - *p = '\0'; - break; - } - p++; - } - snprintf(name, buf_sz, "%s", current_name + lxc_len); - } - - return ret - lxc_len; -} - - -API char * get_pid_cpuset(int pid) -{ - LOGS(""); - int fd; - int ret; - char cpuset_path[PATH_MAX]; - char current_name[NAME_MAX]; - - snprintf(cpuset_path, PATH_MAX, "/proc/%d/cpuset", pid); - - ret = access(cpuset_path, F_OK | R_OK); - if (ret != 0) - return NULL; - - fd = open(cpuset_path, O_RDONLY); - if (fd < 0) { - return NULL; - } - - ret = read(fd, current_name, NAME_MAX - 1); - if (ret < 0) { - close(fd); - return NULL; - } - - current_name[ret - 1] = 0; - close(fd); - - INFO("cpuset path : %s, value : %s", cpuset_path, current_name); - - return strdup(current_name); -} - -API char * read_namespace_link(const char *ns, int pid) -{ - LOGS(""); - char ns_path[PATH_MAX]; - char buf[NAME_MAX]; - int ret; - - snprintf(ns_path, PATH_MAX, "/proc/%d/ns/%s", pid, ns); - - ret = access(ns_path, F_OK); - if (ret != 0) - return NULL; - - ret = readlink(ns_path, buf, NAME_MAX); - if (ret == -1) { - ERROR("Failed to readlink ns file - [%s]", ns_path); - return NULL; - } - - buf[ret] = 0; - - INFO("Read ns link data -pid : %d data : %s", pid, buf); - - return strdup(buf); -} - -// libs/device.c -#define DEV_ITERATE_CONTINUE 0 -API int dev_enumerate_nodes(const char *cname, dev_enumerator enumerator, - void *data) -{ - LOGS(""); - int ret; - FILE *fp;; - char path[PATH_MAX], entry[64]; - - ret = snprintf(path, sizeof(path), - "/sys/fs/cgroup/devices/lxc/%s/devices.list", cname); - - if (ret < 0) { - ERROR("Failed to make pathname"); - return -1; - } - - fp = fopen(path, "r"); - if (fp == NULL) { - ERROR("File open failed: %s(%s)", path, strerror(errno)); - return -1; - } - - while (fgets(entry, sizeof(entry), fp) != NULL) { - int major, minor; - char *next, *ptr = &entry[2]; - - major = strtol(ptr, &next, 10); - minor = strtol(++next, (char **)NULL, 10); - - ret = enumerator(entry[0], major, minor, data); - if (ret != DEV_ITERATE_CONTINUE) - break; - } - - fclose(fp); - - return ret; -} - -API int dev_terminal_enumerator(int type, int major, int minor, void *data) -{ - LOGS(""); - int *dev = (int*)data; - - *dev = minor; - UNUSED(type); - UNUSED(major); - - INFO("Matched device: %c, %d, %d\n", type, major, minor); - - return 1; -} - -// libs/namespace.c -API pid_t get_init_pid(const char *name) -{ - LOGS(""); - char filename[PATH_MAX]; - FILE *fp; - pid_t ret = -1; - - snprintf(filename, sizeof(filename), - "/sys/fs/cgroup/devices/lxc/%s/cgroup.procs", name); - - fp = fopen(filename, "r"); - - if (fp != NULL) { - if (fscanf(fp, "%7d", &ret) < 0) { - ERROR("Failed to read %s\n", filename); - ret = -2; - } - fclose(fp); - } else { - INFO("Unable to access %s\n", filename); - ret = errno; - } - - return ret; -} - - -API pid_t get_zone_pid(const char *name, const char *target) -{ - LOGS(""); - char path[PATH_MAX]; - char cmd[PATH_MAX]; - int res = 0, len; - pid_t ret = -1; - FILE *fp; - - char *line = NULL; - size_t line_len; - - snprintf(path, PATH_MAX, - "/sys/fs/cgroup/cpuset/lxc/%s/cgroup.procs", name); - - res = access(path, F_OK | R_OK); - if (res != 0) { - ERROR("Failed to acess zone cgroup file: %s", path); - return -EINVAL; - } - - if (target == NULL) { - ERROR("Failed to lookup cmdline in zone proc"); - return -EINVAL; - } else { - len = strlen(target); - } - - fp = fopen(path, "r"); - if (fp == NULL) { - ERROR("Failed to open zone cgroup"); - return -1; - } - - while (getline(&line, &line_len, fp) != -1) { - int res; - pid_t pid; - FILE *cmdfp; - char cmdpath[PATH_MAX]; - - res = sscanf(line, "%7d", &pid); - if (res != 1) { - ERROR("Failed to read %s\n", path); - res = -1; - goto out; - } - - if (pid < 0) - continue; - - snprintf(cmdpath, PATH_MAX, "/proc/%d/cmdline", pid); - - if (access(cmdpath, F_OK | R_OK) != 0) - continue; - - cmdfp = fopen(cmdpath, "r"); - if (cmdfp == NULL) { - ERROR("Unable to access %s\n", cmdpath); - continue; - } - - if (fscanf(cmdfp, "%1023s", cmd) < 0) { - ERROR("Failed to read cmdline - pid : %d\n", pid); - continue; - } - - fclose(cmdfp); - - if (strncmp(cmd, target, len) == 0) { - ret = pid; - break; - } - } - out: - fclose(fp); - return ret; -} - -API int open_ns(pid_t pid, const char *name) -{ - LOGS(""); - int fd, ret; - char path[PATH_MAX]; - - ret = snprintf(path, PATH_MAX, "/proc/%d/ns/%s", pid, name); - if (ret < 0 || ret >= PATH_MAX) { - ERROR("Failed to namespace - pid %d, ns: %s ", pid, name); - return -EINVAL; - } - - fd = open(path, O_RDONLY); - if (fd < 0) { - ERROR("failed to open %s\n", path); - return -errno; - } - - return fd; -} - -// vasum/libs/vt.c -#include -#include -static int is_console(int fd) -{ - LOGS(""); - char arg; - - return (isatty(fd) && - (ioctl(fd, KDGKBTYPE, &arg) == 0) && - ((arg == KB_101) || (arg == KB_84))); -} - -static int open_console(const char *path) -{ - int fd; - - fd = open(path, O_RDWR); - if (fd < 0) { - fd = open(path, O_WRONLY); - } - if (fd < 0) { - fd = open(path, O_RDONLY); - } - if (fd < 0) { - return -1; - } - - return fd; -} - -API int get_console_fd(const char *path) -{ - LOGS(""); - int fd; - - if (path) { - fd = open_console(path); - if (fd >= 0) { - return fd; - } - - return -1; - } - - fd = open_console("/dev/tty0"); - if (fd >= 0) { - return fd; - } - - fd = open_console("/dev/console"); - if (fd >= 0) { - return fd; - } - - for (fd = 0; fd < 3; fd++) { - if (is_console(fd)) { - return fd; - } - } - - return -1; -} - -API int vt_switch_terminal(int id) -{ - LOGS(""); - int fd, ret = -1; - - fd = get_console_fd(NULL); - if (fd < 0) { - return -1; - } - - if (ioctl(fd, VT_ACTIVATE, id) < 0) { - goto out; - } - - if (ioctl(fd, VT_WAITACTIVE, id) < 0) { - goto out; - } - - ret = 0; - out: - close(fd); - return ret; -} - -API int vt_find_unused_terminal(void) -{ - LOGS(""); - int fd, nr = -1; - - fd = get_console_fd(NULL); - if (fd < 0) { - perror("Terminal open failed"); - return -1; - } - - if (ioctl(fd, VT_OPENQRY, &nr) < 0) { - perror("VT_OPENQRY failed"); - goto out; - } - - out: - close(fd); - - return nr; -} - -API int vt_query_active_terminal(void) -{ - LOGS(""); - int fd, ret = -1; - struct vt_stat vtstat; - - fd = get_console_fd(NULL); - if (fd < 0) { - return -1; - } - - if (ioctl(fd, VT_GETSTATE, &vtstat) < 0) { - goto out; - } - - ret = vtstat.v_active; - out: - close(fd); - return ret; -} - -// libs/parser.h -struct unit_keyword_callback { - const char *name; - int (*func) (int nargs, char **args); -}; - -struct unit_parser { - struct unit_keyword_callback *kw; -}; - -API int parse_stream(const char *name, struct unit_parser *parser); -// libs/parser.c -#define PARSER_MAXARGS 32 - -#define T_EOF 1 -#define T_STATEMENT 2 -#define T_ARGUMENT 3 -#define T_NEWLINE 7 -#define T_NEWBLOCK 8 - -struct parser_context { - struct unit_keyword_callback *kw; -}; - -struct parser_state { - char *ptr; - char *stmt; - int line; - int nexttoken; - void *context; -}; - -static void parser_init_state(struct parser_state *state, char *line) -{ - state->line = 1; - state->ptr = line; - state->nexttoken = 0; - state->stmt = NULL; - state->context = NULL; -} - -static struct unit_keyword_callback *keyword_lookup(struct parser_context *ctx, - const char *kw) -{ - int i; - - for (i = 0; ctx->kw[i].name != NULL; i++) { - if (!strcmp(ctx->kw[i].name, kw)) { - return &ctx->kw[i]; - } - } - - return NULL; -} - -static int tokenize(struct parser_state *state) -{ - char *x = state->ptr; - char *s, *ss; - - if (state->nexttoken) { - int t = state->nexttoken; - state->nexttoken = 0; - return t; - } - - retry: - state->stmt = s = x; - ss = x + 1; - resume: - while (1) { - switch (*x) { - case 0: - state->nexttoken = T_EOF; - goto textdone; - case '\\': - x++; - switch (*x) { - case 0: - goto textdone; - case 'n': - *s++ = '\n'; - break; - case 'r': - *s++ = '\r'; - break; - case 't': - *s++ = '\t'; - break; - case '\\': - *s++ = '\\'; - break; - case '\r': - /* \ -> line continuation */ - if (x[1] != '\n') { - x++; - continue; - } - case '\n': - /* \ -> line continuation */ - state->line++; - x++; - /* eat any extra whitespace */ - while ((*x == ' ') || (*x == '\t')) - x++; - continue; - default: - /* unknown escape -- just copy */ - *s++ = *x++; - } - continue; - case ',': - x++; - goto textdone; - case '=': - x++; - if (ss == x) { - goto retry; - } - goto textdone; - case ' ': - case '\t': - case '\r': - x++; - if (ss == x) { - goto retry; - } - goto textdone; - case '\n': - x++; - if (ss == x) { - state->ptr = x; - return T_NEWLINE; - } - state->nexttoken = T_NEWLINE; - goto textdone; - case '\'': - case '"': - x++; - for (;;) { - switch (*x) { - case 0: - /* unterminated quoted thing */ - state->ptr = x; - return T_EOF; - case '\'': - case '"': - x++; - goto resume; - default: - *s++ = *x++; - } - } - break; - case '[': - x++; - goto resume; - case ']': - x++; - goto resume; - case '#': - while (*x && (*x != '\n')) - x++; - if (*x == '\n') { - state->ptr = x + 1; - return T_NEWLINE; - } else { - state->ptr = x; - return T_EOF; - } - break; - default: - *s++ = *x++; - } - } - - textdone: - state->ptr = x; - *s = 0; - return T_STATEMENT; -} - -static int parse_statement(struct parser_context *ctx, int argc, char **argv, - int (*func) (int argc, char **argv)) -{ - struct parser_state state; - char *args[PARSER_MAXARGS]; - int i; - int ret = 0; - UNUSED(ctx); - - for (i = 0; i < argc; i++) { - int nargs, done, rc; - done = nargs = 0; - parser_init_state(&state, argv[i]); - - while (!done) { - int token = tokenize(&state); - switch (token) { - case T_EOF: - if (nargs && func) { - rc = func(nargs, args); - if (rc < 0) { - WARN("Key word callback error"); - } - nargs = 0; - } - done = 1; - break; - case T_STATEMENT: - if (nargs < PARSER_MAXARGS) { - args[nargs++] = state.stmt; - } - break; - } - } - } - - return ret; -} - -API int parse_stream_core(struct parser_context *ctx, char *s) -{ - LOGS(""); - struct unit_keyword_callback *kw; - struct parser_state state; - char *args[PARSER_MAXARGS]; - int nargs, rc; - - nargs = 0; - parser_init_state(&state, s); - - for (;;) { - int token = tokenize(&state); - switch (token) { - case T_EOF: - return 0; - case T_NEWLINE: - if (nargs) { - if ((kw = keyword_lookup(ctx, args[0])) != NULL) { - rc = parse_statement(ctx, nargs - 1, - &args[1], - kw->func); - if (rc < 0) { - return -EINVAL; - } - } - - nargs = 0; - } - break; - case T_STATEMENT: - if (nargs < PARSER_MAXARGS) { - args[nargs++] = state.stmt; - } - break; - } - } - - return 0; -} - -/* reads a file, making sure it is terminated with \n \0 */ -static char *open_stream(const char *name, unsigned int *_sz) -{ - int sz, fd; - char *data = NULL; - - fd = open(name, O_RDONLY); - if (fd < 0) - return NULL; - - sz = lseek(fd, 0, SEEK_END); - if (sz < 0) - goto oops; - - if (lseek(fd, 0, SEEK_SET) != 0) - goto oops; - - data = (char *)malloc(sz + 2); - if (data == 0) - goto oops; - - if (read(fd, data, sz) != sz) - goto oops; - - close(fd); - - data[sz] = '\n'; - data[sz + 1] = 0; - if (_sz) - *_sz = sz; - - return data; - - oops: - close(fd); - if (data != 0) - free(data); - - return NULL; -} - -API int parse_stream(const char *name, struct unit_parser *parser) -{ - LOGS(""); - char *stream; - struct parser_context *ctx; - - ctx = (struct parser_context *)malloc(sizeof(struct parser_context)); - if (ctx == NULL) { - return -ENOMEM; - } - - ctx->kw = parser->kw; - - /* File open & return file context */ - stream = open_stream(name, NULL); - if (stream == NULL) { - free(ctx); - return -1; - } - - parse_stream_core(ctx, stream); - - free(stream); - free(ctx); - - return 0; -} -API struct vsm_netdev *alloc_netdev(struct vsm_zone * /*zone*/, vsm_netdev_type_t /*type*/, const char * /*netdev_name*/) { - LOGS(""); - return NULL; -} -API void enter_to_ns(pid_t /*pid*/, char * /*name*/) { - LOGS(""); -} - -// dummy-ops -static int dummy_create_zone(vsm_context_h /*ctx*/, const char * /*zone_name*/, - const char * /*template*/, int /*flags*/) -{ - return -VSM_ERROR_NOT_SUPPORTED; -} - -static int dummy_destroy_zone(vsm_context_h /*ctx*/, const char * /*zone_name*/, int /*force*/) -{ - return -VSM_ERROR_NOT_SUPPORTED; -} - -static int dummy_start_zone(vsm_context_h /*ctx*/, const char * /*zone_name*/) -{ - return -VSM_ERROR_NOT_SUPPORTED; -} - -static int dummy_shutdown_zone(vsm_context_h /*ctx*/, const char * /*zone_name*/, int /*force*/) -{ - return -VSM_ERROR_NOT_SUPPORTED; -} - -static int dummy_lock_zone(vsm_context_h /*ctx*/, const char * /*zone_name*/, int /*shutdown*/) -{ - return -VSM_ERROR_NOT_SUPPORTED; -} - -static int dummy_unlock_zone(vsm_context_h /*ctx*/, const char * /*zone_name*/) -{ - return -VSM_ERROR_NOT_SUPPORTED; -} - -static int dummy_set_foreground(vsm_zone_h zone) -{ - if (zone == NULL) - return -VSM_ERROR_INVALID; - - if (zone->parent == zone) { - return VSM_ERROR_NONE; - } - return -VSM_ERROR_NO_OBJECT; -} - -static vsm_zone_h dummy_get_foreground(vsm_context_h ctx) -{ - if (ctx == NULL) { - errno = EINVAL; - return NULL; - } - - return ctx->root_zone; -} - -static int dummy_iterate_zone(vsm_context_h ctx, vsm_zone_iter_cb callback, void *user_data) -{ - if (callback) { - callback(ctx->root_zone, user_data); - } - return VSM_ERROR_NONE; -} - -static vsm_zone_h dummy_lookup_zone_by_name(vsm_context_h ctx, const char *name) -{ - if (strcmp(name, "") != 0) { - errno = ESRCH; - return NULL; - } - - return ctx->root_zone; -} - -static vsm_zone_h dummy_lookup_zone_by_pid(vsm_context_h ctx, pid_t /*pid*/) -{ - if (ctx == NULL) - return NULL; - - return ctx->root_zone; -} - -static int dummy_attach_zone(vsm_context_h ctx, const char *zone_name, - vsm_attach_command_s * command, - vsm_attach_options_s * opts, - pid_t * attached_process) -{ - pid_t pid; - struct vsm_attach_options_s options; - - if (command == NULL || command->exec == NULL || zone_name == NULL) { - ERROR("Invalid arguments"); - ctx->error = VSM_ERROR_INVALID; - return -VSM_ERROR_INVALID; - } - - if (strcmp("", zone_name) != 0) { - ctx->error = VSM_ERROR_INVALID; - return -VSM_ERROR_INVALID; - } - - if (opts == NULL) { - opts = &options; - opts->uid = getuid(); - opts->gid = getgid(); - opts->env_num = 0; - opts->extra_env = NULL; - } - - pid = fork(); - if (pid == 0) { - if (opts->extra_env != NULL) { - while (*opts->extra_env) - putenv(*opts->extra_env++); - } - - if (getuid() == 0 && opts->uid != 0) { - if (setuid(opts->uid) != 0) { - ERROR("Failed to set uid : %d", opts->uid); - } - } else { - WARN("setuid() is not permitted"); - } - - if (getgid() == 0 && opts->gid != 0) { - if (setgid(opts->gid) != 0) { - ERROR("Failed to set gid : %d", opts->gid); - } - } else { - WARN("setgid() is not permitted"); - } - - if (execvp(command->exec, command->argv) < 0) { - ERROR("exevp failed : %s, %s", command->exec, - strerror(errno)); - exit(EXIT_FAILURE); - } - } else { - *attached_process = pid; - } - - return VSM_ERROR_NONE; -} - -static int dummy_attach_zone_wait(vsm_context_h ctx, const char *zone_name, - vsm_attach_command_s * command, - vsm_attach_options_s * opts) -{ - pid_t pid = 0; - int ret, status; - - ret = dummy_attach_zone(ctx, zone_name, command, opts, &pid); - if (ret != VSM_ERROR_NONE) { - ERROR("API Failed."); - return ret; - } - - status = wait_for_pid_status(pid); - if (status == -1) { - ctx->error = VSM_ERROR_GENERIC; - return -VSM_ERROR_GENERIC; - } - - INFO("attached process extied : pid - %d, exit code : %d", pid, - WEXITSTATUS(status)); - - return status; -} - -static vsm_zone_h dummy_join_zone(vsm_zone_h zone) -{ - if (zone == NULL) { - errno = EINVAL; - return NULL; - } - if (zone != zone->parent) { - errno = EINVAL; - return NULL; - } - - return zone; -} - -static int dummy_is_equivalent_zone(vsm_context_h /*ctx*/, pid_t /*pid*/) -{ - return 1; -} - -static int dummy_get_host_pid(vsm_zone_h zone, pid_t pid) -{ - if (zone == zone->parent) - return pid; - - return -VSM_ERROR_NO_OBJECT; -} - -static int dummy_grant_device(vsm_zone_h /*zone*/, const char * /*path*/, uint32_t /*flags*/) -{ - return -VSM_ERROR_NOT_SUPPORTED; -} - -static int dummy_revoke_device(vsm_zone_h /*zone*/, const char * /*path*/) -{ - return -VSM_ERROR_NOT_SUPPORTED; -} - -static int dummy_declare_file(vsm_context_h /*ctx*/, vsm_fso_type_t /*ftype*/, - const char * /*path*/, int /*flags*/, vsm_mode_t /*mode*/) -{ - return VSM_ERROR_NONE; -} - -static int dummy_declare_link(vsm_context_h /*ctx*/, const char *source, - const char * /*target*/) -{ - int ret; - - ret = access(source, F_OK); - if (ret != 0) - return -VSM_ERROR_NO_OBJECT; - - return VSM_ERROR_NONE; -} - -struct vasum_ops dummy_ops; -static int dummy_ops_init() { - dummy_ops.create_zone = dummy_create_zone; - dummy_ops.destroy_zone = dummy_destroy_zone; - dummy_ops.start_zone = dummy_start_zone; - dummy_ops.shutdown_zone = dummy_shutdown_zone; - dummy_ops.lock_zone = dummy_lock_zone; - dummy_ops.unlock_zone = dummy_unlock_zone; - dummy_ops.set_foreground = dummy_set_foreground; - dummy_ops.get_foreground = dummy_get_foreground; - dummy_ops.iterate_zone = dummy_iterate_zone; - dummy_ops.lookup_zone_by_name = dummy_lookup_zone_by_name; - dummy_ops.lookup_zone_by_pid = dummy_lookup_zone_by_pid; - dummy_ops.attach_zone = dummy_attach_zone; - dummy_ops.attach_zone_wait = dummy_attach_zone_wait; - dummy_ops.join_zone = dummy_join_zone; - dummy_ops.is_equivalent_zone = dummy_is_equivalent_zone; - dummy_ops.get_host_pid = dummy_get_host_pid; - dummy_ops.grant_device = dummy_grant_device; - dummy_ops.revoke_device = dummy_revoke_device; - dummy_ops.declare_file = dummy_declare_file; - dummy_ops.declare_link = dummy_declare_link; - return 0; -} -int dummy_ops_init_i = dummy_ops_init(); - - -} //extern "C" diff --git a/wrapper/wrapper-compatibility.h b/wrapper/wrapper-compatibility.h deleted file mode 100644 index 2527289..0000000 --- a/wrapper/wrapper-compatibility.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved - * - * Contact: Krzysztof Dynowski - * - * 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 Krzysztof Dynowski (k.dynowski@samsung.com) - * @brief Vasum old API compatibility functions - */ - -#ifndef __CLIENT_WRAPPER_COMPAT__ -#define __CLIENT_WRAPPER_COMPAT__ - -#include "vasum.h" -#include - -extern "C" { -typedef int (*fp_create_zone) (vsm_context_h ctx, const char *zone_name, - const char *template_name, int flag); -typedef int (*fp_destroy_zone) (vsm_context_h ctx, const char *zone_name, - int force); -typedef int (*fp_start_zone) (vsm_context_h ctx, const char *zone_name); -typedef int (*fp_shutdown_zone) (vsm_context_h ctx, const char *zone_name, - int force); -typedef int (*fp_lock_zone) (vsm_context_h ctx, const char *zone_name, - int shutdown); -typedef int (*fp_unlock_zone) (vsm_context_h ctx, const char *zone_name); -typedef int (*fp_set_foreground) (vsm_zone_h zone); -typedef vsm_zone_h(*fp_get_foreground) (vsm_context_h ctx); -typedef int (*fp_iterate_zone) (vsm_context_h ctx, vsm_zone_iter_cb callback, - void *user_data); -typedef vsm_zone_h(*fp_lookup_zone_by_name) (vsm_context_h ctx, - const char *name); -typedef vsm_zone_h(*fp_lookup_zone_by_pid) (vsm_context_h ctx, pid_t pid); -typedef int (*fp_attach_zone) (vsm_context_h ctx, const char *zone_name, - vsm_attach_command_s * command, - vsm_attach_options_s * opt, - pid_t * attached_process); -typedef int (*fp_attach_zone_wait) (vsm_context_h ctx, const char *zone_name, - vsm_attach_command_s * command, - vsm_attach_options_s * opt); -typedef vsm_zone_h(*fp_join_zone) (vsm_zone_h zone); -typedef int (*fp_is_equivalent_zone) (vsm_context_h ctx, pid_t pid); -typedef int (*fp_get_host_pid) (vsm_zone_h zone, pid_t pid); -typedef int (*fp_grant_device) (vsm_zone_h zone, const char *path, - uint32_t flags); -typedef int (*fp_revoke_device) (vsm_zone_h zone, const char *path); -typedef int (*fp_declare_file) (vsm_context_h ctx, vsm_fso_type_t ftype, - const char *path, int flags, vsm_mode_t mode); -typedef int (*fp_declare_link) (vsm_context_h ctx, const char *source, - const char *target); -struct vasum_ops { - fp_create_zone create_zone; - fp_destroy_zone destroy_zone; - fp_start_zone start_zone; - fp_shutdown_zone shutdown_zone; - fp_lock_zone lock_zone; - fp_unlock_zone unlock_zone; - fp_set_foreground set_foreground; - fp_get_foreground get_foreground; - fp_iterate_zone iterate_zone; - fp_lookup_zone_by_name lookup_zone_by_name; - fp_lookup_zone_by_pid lookup_zone_by_pid; - fp_attach_zone attach_zone; - fp_attach_zone_wait attach_zone_wait; - fp_join_zone join_zone; - fp_get_host_pid get_host_pid; - fp_is_equivalent_zone is_equivalent_zone; - fp_grant_device grant_device; - fp_revoke_device revoke_device; - fp_declare_file declare_file; - fp_declare_link declare_link; -}; - -#define SERVICEPATH "\0/domain-control/service.sock" -struct mainloop { - int epfd; - pthread_mutex_t ml_mutex; - pthread_rwlock_t lock; - struct adt_list watches; -}; -struct mxe_emple; -struct mxe_endpoint; -struct mxe_emple { - int signature; - int refcnt; - void *callback; - void *data; - struct mxe_proxy *proxy; - struct adt_list queue; -}; -struct mxe_engine { - void *data; - struct mainloop *mainloop; - pthread_rwlock_t endpoint_lock; - struct adt_list endpoints; -}; -struct mxe_endpoint { - int fd; - int type; - struct mxe_engine *engine; - pthread_rwlock_t queue_lock; - pthread_mutex_t rd_mutex; - pthread_mutex_t wr_mutex; - struct adt_list queue; - struct adt_list list; -}; - -typedef enum { - ML_EVT_IN = EPOLLIN, - ML_EVT_OUT = EPOLLOUT, - ML_EVT_RDHUP = EPOLLRDHUP, - ML_EVT_ERROR = EPOLLERR, - ML_EVT_HUP = EPOLLHUP, - ML_EVT_ET = EPOLLET -}mainloop_event; - -typedef int (*dev_enumerator)(int type, int major, int minor, void *data); -typedef int (*mainloop_callback)(int fd, mainloop_event event, void *data, struct mainloop *mainloop); - -struct mainloop *mainloop_create(void); -struct mxe_endpoint *mxe_create_client(struct mxe_engine *engine, const char * /*addr*/); -struct mxe_engine *mxe_prepare_engine(struct mainloop *mainloop, void *data); - -int wait_for_pid_status(pid_t pid); - -int vsm_add_state_changed_callback(vsm_context_h /*ctx*/, vsm_zone_state_changed_cb /*callback*/, void * /*user_data*/); -int vsm_del_state_changed_callback(vsm_context_h /*ctx*/, int /*id*/); -const char * vsm_get_zone_rootpath(vsm_zone_h /*zone*/); -const char * vsm_get_zone_name(vsm_zone_h /*zone*/); -int vsm_is_host_zone(vsm_zone_h /*zone*/); -vsm_zone_h vsm_join_zone(vsm_zone_h zone); -int vsm_canonicalize_path(const char *input_path, char **output_path); - -} //extern "C" - -#endif diff --git a/wrapper/wrapper.cpp b/wrapper/wrapper.cpp deleted file mode 100644 index c3a071f..0000000 --- a/wrapper/wrapper.cpp +++ /dev/null @@ -1,818 +0,0 @@ -/* - * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved - * - * Contact: Krzysztof Dynowski - * - * 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 Krzysztof Dynowski (k.dynowski@samsung.com) - * @brief Vasum old API wrapper to slp client lib - */ - -#define __VASUM_WRAPPER_SOURCE__ -#include -#include -#include - -#include "config.hpp" -#include "vasum-client-impl.hpp" -#include "logger/logger.hpp" -#include "logger/backend-journal.hpp" - -#include "wrapper-compatibility.h" - -struct WrappedZone -{ - Client *client; - VsmZone zone; - struct vsm_zone vz; - std::vector netdevs; -}; - -struct WrappedContext -{ - Client *client; - vsm_context hq_ctx; - struct vsm_zone hq_root; - std::vector zones; -}; - -static struct -{ - int done; -} wrap; - - -#ifndef offsetof -#define offsetof(type, memb) ((size_t)&((type *)0)->memb) -#endif -#ifdef container_of -#undef container_of -#endif -#ifndef container_of -#define container_of(ptr, type, memb) (\ - (type *)((char *)(ptr) - offsetof(type, memb))) -#endif - -#define UNUSED(x) ((void)(x)) - -#define vsm_attach_command_t vsm_attach_command_s -#define vsm_attach_options_t vsm_attach_options_s - -void __attribute__ ((constructor)) wrapper_load(void); -void __attribute__ ((destructor)) wrapper_unload(void); -static void init_wrapper(); -extern struct vasum_ops dummy_ops; - -using namespace logger; -void wrapper_load(void) -{ - Logger::setLogLevel(LogLevel::TRACE); - Logger::setLogBackend(new SystemdJournalBackend()); - LOGI("wrapper_load"); - init_wrapper(); -} - -void wrapper_unload(void) -{ - LOGI("wrapper_unload"); -} - -static void callcheck() -{ - init_wrapper(); -} - -void init_wrapper() -{ - if (wrap.done) return ; - memset(&wrap, 0, sizeof(wrap)); - wrap.done = 1; - LOGS(""); -} - -static struct vsm_zone* wrap_vsm_zone(WrappedContext *w, Zone zone, bool create = false) -{ - if (zone == NULL) { - return NULL; - } - for (auto& zw : w->zones) { - if (zw.zone == zone) { - return &zw.vz; - } - } - if (create) { - w->zones.push_back(WrappedZone()); - WrappedZone& zw = w->zones.back(); - zw.client = w->client; - zw.zone = zone; - zw.vz.name = zone->id; - zw.vz.id = 0; - zw.vz.type = NULL; - zw.vz.user_data = NULL; - zw.vz.rootfs_path = zone->rootfs_path; - zw.vz.parent = &zw.vz; - LOGI("return (create) zone " << zone->id); - return &w->zones.back().vz; - } - LOGE("return zone NULL"); - return NULL; -} - -static int wrap_error(VsmStatus st, const Client *c) -{ - if (st == VSMCLIENT_SUCCESS) LOGI("return success " << st); - else LOGE("return error=" << st << ", msg=" << (c ? c->vsm_get_status_message() : "n/a")); - switch (st) { - case VSMCLIENT_SUCCESS: return VSM_ERROR_NONE; - case VSMCLIENT_CUSTOM_ERROR: return -VSM_ERROR_GENERIC; - case VSMCLIENT_IO_ERROR: return -VSM_ERROR_IO; - case VSMCLIENT_OPERATION_FAILED: return -VSM_ERROR_NOT_PERMITTED; - case VSMCLIENT_INVALID_ARGUMENT: return -VSM_ERROR_INVALID; - case VSMCLIENT_OTHER_ERROR: return -VSM_ERROR_GENERIC; - } - return -VSM_ERROR_GENERIC; -} - -static void init_context_wrap(WrappedContext *w) -{ - w->client = new Client(); - VsmStatus st = w->client->connectSystem(); - wrap_error(st, w->client); - - memset(&w->hq_ctx, 0, sizeof(w->hq_ctx)); - memset(&w->hq_root, 0, sizeof(w->hq_root)); - - vsm_context *ctx = &w->hq_ctx; - adt_init_list(&ctx->listeners); - //init root_zone - ctx->root_zone = &w->hq_root; - ctx->root_zone->name = (char*)""; - ctx->root_zone->id = 0; - ctx->root_zone->rootfs_path = (char*)"/"; - - ctx->root_zone->terminal = -1; - ctx->root_zone->state = VSM_ZONE_STATE_RUNNING; - ctx->root_zone->user_data = ctx->root_zone; - - ctx->root_zone->parent = ctx->root_zone; - ctx->root_zone->ctx = ctx; - - pthread_rwlock_init(&ctx->root_zone->lock, NULL); - adt_init_list(&ctx->root_zone->netdevs); - adt_init_list(&ctx->root_zone->devices); - adt_init_list(&ctx->root_zone->children); - - pthread_rwlock_init(&ctx->lock, NULL); - adt_init_list(&ctx->listeners); - adt_init_list(&ctx->sc_listeners); - adt_init_list(&ctx->ev_listeners); - - //struct mainloop *mainloop = mainloop_create(); - //struct mxe_engine *engine = mxe_prepare_engine(mainloop, ctx); - //struct mxe_endpoint *ep = mxe_create_client(engine, SERVICEPATH); - - ctx->foreground_zone = ctx->root_zone; - ctx->vsm_ops = &dummy_ops; - ctx->error = VSM_ERROR_NONE; - //ctx->data = ep; -} - -extern "C" { -API void vsm_string_free(VsmString string); -API void vsm_array_string_free(VsmArrayString astring); - -API vsm_context_h vsm_create_context(void) -{ - LOGS(""); - callcheck(); - WrappedContext *w = new WrappedContext(); - init_context_wrap(w); - - vsm_context *ctx = &w->hq_ctx; - return ctx; -} - -API int vsm_cleanup_context(vsm_context_h ctx) -{ - LOGS(""); - callcheck(); - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - if (w->client != NULL) { - delete w->client; - w->client = NULL; - } - for (auto& zw : w->zones) { - zw.netdevs.clear(); - } - w->zones.clear(); - pthread_rwlock_destroy(&ctx->lock); - delete w; - return VSM_ERROR_NONE; -} - -static const char *const vsm_error_strtab[] = { - "No error", - "Undefined error", - "Invalid", - "Operation cancelled", - "Operation aborted", - "Connection refused", - "Object exists", - "Resource busy", - "Input/Output error", - "Timeout", - "Overflow", - "Out of memory", - "Out of range", - "Operation not permitted", - "Function not implemented", - "Operation not supported", - "Access denied", - "No object found", - "Bad state" -}; - -API vsm_error_e vsm_last_error(struct vsm_context *ctx) -{ - if (ctx) - return ctx->error; - return static_cast(-1); -} - -API int vsm_get_poll_fd(struct vsm_context *ctx) -{ - LOGS(""); - callcheck(); - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - UNUSED(w); - //FIXME Client should create Dispatcher and pass to IPCConnection - // now: IPCConnection has field ThreadWrapper - //return w->client->getEventPoll().getPollFD(); - return -1; -} -API int vsm_enter_eventloop(struct vsm_context *ctx, int flags, int timeout) -{ - LOGS(""); - callcheck(); - UNUSED(flags); - UNUSED(timeout); - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - UNUSED(w); - //FIXME Client should create Dispatcher and pass to IPCConnection - // now: IPCConnection has field ThreadWrapper - //TODO Use EventPoll from Dispatcher - return 0; -} - -API int vsm_create_zone(struct vsm_context *ctx, const char *zone_name, const char *template_name, int flag) -{ - LOGS("create_zone " << zone_name); - callcheck(); - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - UNUSED(flag); - //template_name = NULL; //template name not supported by libvasum-client - if (!w->client) return VSM_ERROR_GENERIC; - VsmStatus st = w->client->vsm_create_zone(zone_name, template_name); - if (st != VSMCLIENT_SUCCESS) { - LOGE("vsm_create_zone(" << zone_name << ") = " << st); - } - return wrap_error(st, w->client); -} - -API int vsm_destroy_zone(struct vsm_context *ctx, const char *zone_name, int force) -{ - LOGS("zone=" << zone_name); - callcheck(); - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - UNUSED(force); - if (!w->client) return VSM_ERROR_GENERIC; - VsmStatus st = w->client->vsm_destroy_zone(zone_name); - if (st == VSMCLIENT_SUCCESS) { - auto zonebyname = [zone_name](const WrappedZone& v) { - return static_cast(v.zone)->id == zone_name; - }; - auto zonelist = std::remove_if(w->zones.begin(), w->zones.end(), zonebyname); - w->zones.erase(zonelist); - } - return wrap_error(st, w->client); -} - -API int vsm_start_zone(struct vsm_context *ctx, const char *zone_name) -{ - LOGS("zone=" << zone_name); - callcheck(); - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - if (!w->client) return VSM_ERROR_GENERIC; - VsmStatus st = w->client->vsm_start_zone(zone_name); - return wrap_error(st, w->client); -} - -API int vsm_shutdown_zone(struct vsm_context *ctx, const char *zone_name, int force) -{ - LOGS("zone=" << zone_name); - callcheck(); - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - UNUSED(force); - if (!w->client) return VSM_ERROR_GENERIC; - VsmStatus st = w->client->vsm_shutdown_zone(zone_name); - return wrap_error(st, w->client); -} - -API int vsm_lock_zone(struct vsm_context *ctx, const char *zone_name, int shutdown) -{ - LOGS("zone=" << zone_name); - callcheck(); - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - UNUSED(shutdown); - if (!w->client) return VSM_ERROR_GENERIC; - VsmStatus st = w->client->vsm_lock_zone(zone_name); - return wrap_error(st, w->client); -} - -API int vsm_unlock_zone(struct vsm_context *ctx, const char *zone_name) -{ - LOGS("zone=" << zone_name); - callcheck(); - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - if (!w->client) return VSM_ERROR_GENERIC; - VsmStatus st = w->client->vsm_lock_zone(zone_name); - return wrap_error(st, w->client); -} - -API int vsm_set_foreground(struct vsm_zone *zone) -{ - LOGS(""); - callcheck(); - WrappedZone *w = container_of(zone, WrappedZone, vz); - if (!w->client) return VSM_ERROR_GENERIC; - VsmStatus st = w->client->vsm_set_active_zone(zone->name); - return wrap_error(st, w->client); -} - -//execute command in specified zone -API int vsm_attach_zone(struct vsm_context *ctx, - const char *zone_name, - vsm_attach_command_t *command, - vsm_attach_options_t *opts, - pid_t *attached_process) -{ - return dummy_ops.attach_zone(ctx, zone_name, command, opts, - attached_process); -} - -//execute command in specified zone and wait -API int vsm_attach_zone_wait(struct vsm_context *ctx, - const char *zone_name, - vsm_attach_command_t *command, - vsm_attach_options_t *opts) -{ - return dummy_ops.attach_zone_wait(ctx, zone_name, command, opts); -} - -API int vsm_iterate_zone(struct vsm_context *ctx, void (*callback)(struct vsm_zone *zone, void *user_data), void *user_data) -{ - LOGS(""); - callcheck(); - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - if (!w->client) return -VSM_ERROR_GENERIC; - callback(ctx->root_zone, user_data); - for (auto& z : w->zones) { - LOGI("iterate callback zone: " << static_cast(z.zone)->id); - callback(&z.vz, user_data); - } - return 0; -} - -API struct vsm_zone *vsm_lookup_zone_by_name(struct vsm_context *ctx, const char *path) -{ - LOGS("name=" << path); - callcheck(); - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - Zone zone; - if (!w->client) return NULL; - //CHECK if path is same as zone_name - if (w->client->vsm_lookup_zone_by_id(path, &zone) != VSMCLIENT_SUCCESS) - return NULL; - return wrap_vsm_zone(w, zone, true); -} - -//supposed return ref to internal struct -API struct vsm_zone *vsm_lookup_zone_by_pid(struct vsm_context *ctx, pid_t pid) -{ - LOGS("pid=" << pid); - callcheck(); - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - Zone zone; - VsmString id; - VsmStatus st; - if (!w->client) return NULL; - if ((st = w->client->vsm_lookup_zone_by_pid(pid, &id)) != VSMCLIENT_SUCCESS) { - wrap_error(st, w->client); - return NULL; - } - LOGI("found zone(pid=" << pid << ")='" << id << "'"); - if (::strcmp(id, "host") == 0) { - return w->hq_ctx.root_zone; - } - w->client->vsm_lookup_zone_by_id(id, &zone); //zone is malloced - return wrap_vsm_zone(w, zone); -} - -API int vsm_add_state_changed_callback(struct vsm_context *ctx, vsm_zone_state_changed_cb callback, void *user_data) -{ - LOGS(""); - callcheck(); - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - VsmSubscriptionId subscriptionId; - - auto dbus_cb = [=](const char* id, const char* dbusAddress, void* data) -> - void { - Zone zone; - //TODO what are valid state, event - vsm_zone_state_t t = VSM_ZONE_STATE_RUNNING; - UNUSED(dbusAddress); - w->client->vsm_lookup_zone_by_id(id, &zone); - callback(wrap_vsm_zone(w, zone), t, data); - }; - w->client->vsm_add_state_callback(dbus_cb, user_data, &subscriptionId); - return (int)subscriptionId; -} - -API int vsm_del_state_changed_callback(struct vsm_context *ctx, int handle) -{ - LOGS(""); - callcheck(); - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - VsmSubscriptionId subscriptionId = (VsmSubscriptionId)handle; - VsmStatus st = w->client->vsm_del_state_callback(subscriptionId); - return wrap_error(st, w->client); -} - -API int vsm_grant_device(struct vsm_zone *dom, const char *name, uint32_t flags) -{ - LOGS(""); - callcheck(); - WrappedZone *w = container_of(dom, WrappedZone, vz); - const char *id = dom->name; - Zone zone; - w->client->vsm_lookup_zone_by_id(id, &zone); - VsmStatus st = w->client->vsm_grant_device(id, name, flags); - return wrap_error(st, w->client); -} - -API int vsm_revoke_device(struct vsm_zone *dom, const char *name) -{ - LOGS(""); - callcheck(); - WrappedZone *w = container_of(dom, WrappedZone, vz); - const char *id = dom->name; - VsmStatus st = w->client->vsm_revoke_device(id, name); - return wrap_error(st, w->client); -} - -API struct vsm_netdev *vsm_create_netdev(struct vsm_zone *zone, vsm_netdev_type_t type, const char *target, const char *netdev) -{ - LOGS(""); - callcheck(); - UNUSED(zone); - UNUSED(type); - UNUSED(target); - UNUSED(netdev); - - WrappedZone *w = container_of(zone, WrappedZone, vz); - const char *id = zone->name; - VsmStatus st; - if (type == VSM_NETDEV_VETH) - st = w->client->vsm_create_netdev_veth(id, target, netdev); - else if (type == VSM_NETDEV_PHYS) - st = w->client->vsm_create_netdev_phys(id, netdev); - else if (type == VSM_NETDEV_MACVLAN) // macvlan_mode from if_link.h - st = w->client->vsm_create_netdev_macvlan(id, target, netdev, MACVLAN_MODE_BRIDGE); - else { - LOGE("Invalid arguments"); - //ctx->error = VSM_ERROR_INVALID; - return NULL; - } - - if (st != VSMCLIENT_SUCCESS) { - LOGE("vsm_create_netdev(" << netdev << ") = " << st); - return NULL; - } - - vsm_netdev vnd; - vnd.zone = zone; - vnd.name = (char*)netdev; //FIXME? copy content of string - vnd.type = type; - w->netdevs.push_back(vnd); //copy pushed to vector - return &w->netdevs.back(); //pointer to struct on vector -} - -API int vsm_destroy_netdev(vsm_netdev_h) -{ - LOGS(""); - return 0; -} - -API int vsm_iterate_netdev(struct vsm_zone *zone, void (*callback)(struct vsm_netdev *, void *user_data), void *user_data) -{ - LOGS(""); - callcheck(); - WrappedZone *w = container_of(zone, WrappedZone, vz); - for (auto nd : w->netdevs) { - callback(&nd, user_data); - } - return 0; -} - -API struct vsm_netdev *vsm_lookup_netdev_by_name(struct vsm_zone *zone, const char *name) -{ - LOGS(""); - callcheck(); - WrappedZone *w = container_of(zone, WrappedZone, vz); - Netdev nd; - VsmStatus st = w->client->vsm_lookup_netdev_by_name(zone->name, name, &nd); - if (st == VSMCLIENT_SUCCESS) { - auto devbyname = [name](const vsm_netdev& v) {return ::strcmp(v.name, name) == 0;}; - auto devlist = std::find_if(w->netdevs.begin(), w->netdevs.end(), devbyname); - if (devlist != w->netdevs.end()) { - return &devlist[0]; - } - } - return NULL; -} - -API int vsm_declare_file(struct vsm_context *ctx, vsm_fso_type_t ftype, const char *path, int flags, vsm_mode_t mode) -{ - LOGS(""); - callcheck(); -/* Old implementation is following: (but implemented in server) - args.oldpath = oldpath; - args.newpath = newpath; - ret = iterate_running_zone("/sys/fs/cgroup/cpuset/lxc", file_resource, &args); -*/ - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - VsmArrayString ids = NULL; - VsmFileType type; - switch (ftype) { - case VSM_FSO_TYPE_DIR: /**< Directoy type */ - type = VSMFILE_DIRECTORY; - break; - case VSM_FSO_TYPE_REG: /**< Regular file type */ - type = VSMFILE_REGULAR; - break; - case VSM_FSO_TYPE_FIFO: /**< Fifo file type */ - type = VSMFILE_FIFO; - break; - case VSM_FSO_TYPE_SOCK: /**< Socket file type */ - return VSM_ERROR_NONE; - case VSM_FSO_TYPE_DEV: /**< Device node type */ - return VSM_ERROR_NONE; - default: - return VSM_ERROR_NONE; - } - w->client->vsm_get_zone_ids(&ids); - if (ids != NULL) { - for (VsmString* id = ids; *id; ++id) { - VsmStatus st = w->client->vsm_declare_file(*id, type, path, (int32_t)flags, (mode_t)mode, NULL); - if (st != VSMCLIENT_SUCCESS) { - wrap_error(st, w->client); - } - } - } - vsm_array_string_free(ids); - return VSM_ERROR_NONE; -} - -API int vsm_declare_link(struct vsm_context *ctx, const char *source, const char *target) -{ - LOGS("src=" << source << ", dst=" << target); - callcheck(); -/* Old implementation is following: (but implemented in server) - args.oldpath = oldpath; - args.newpath = newpath; - ret = iterate_running_zone("/sys/fs/cgroup/cpuset/lxc", link_resource, &args); -*/ - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - VsmArrayString ids = NULL; - w->client->vsm_get_zone_ids(&ids); - if (ids != NULL) - for (VsmString* id = ids; *id; ++id) { - VsmStatus st = w->client->vsm_declare_link(source, *id, target, NULL); - if (st != VSMCLIENT_SUCCESS) - wrap_error(st, w->client); - } - vsm_array_string_free(ids); - return VSM_ERROR_NONE; -} - -API int vsm_declare_mount(struct vsm_context *ctx, - const char *source, - const char *target, - const char *fstype, - unsigned long flags, - const void *data) -{ - LOGS(""); - callcheck(); -/* Old implementation is following: (but implemented in server) - args.oldpath = oldpath; - args.newpath = newpath; - ret = iterate_running_zone("/sys/fs/cgroup/cpuset/lxc", mount_resource, &args); -*/ - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - VsmArrayString ids = NULL; - w->client->vsm_get_zone_ids(&ids); - if (ids != NULL) { - for (VsmString* id = ids; *id; ++id) { - VsmStatus st = w->client->vsm_declare_mount(source, *id, target, fstype, flags, (const char *)data, NULL); - if (st != VSMCLIENT_SUCCESS) { - wrap_error(st, w->client); - } - } - } - vsm_array_string_free(ids); - return VSM_ERROR_NONE; -} - -API const char * vsm_get_zone_rootpath(vsm_zone_h zone) -{ - LOGS(""); - return zone == NULL ? NULL : zone->rootfs_path; -} -API const char * vsm_get_zone_name(vsm_zone_h zone) -{ - LOGS(""); - return zone == NULL ? NULL : zone->name; -} -API int vsm_is_host_zone(vsm_zone_h zone) -{ - LOGS(""); - if (zone == NULL) - return -VSM_ERROR_INVALID; - - LOGI("zone->parent == zone is " << (zone->parent == zone ? 1 : 0)); - return zone->parent == zone ? 1 : 0; -} -API vsm_zone_h vsm_join_zone(vsm_zone_h /*zone*/) -{ - LOGS(""); - return NULL; -} -API int vsm_canonicalize_path(const char *input_path, char **output_path) -{ - LOGS(""< VSM_MAX_ERROR) { - return NULL; - } - return vsm_error_strtab[error]; -} - -API struct vsm_zone *vsm_lookup_zone_by_terminal_id(struct vsm_context *ctx, int terminal) -{ - LOGS("terminal=" << terminal); - callcheck(); - WrappedContext *w = container_of(ctx, WrappedContext, hq_ctx); - Zone zone; - VsmString id; - if (!w->client) return NULL; - if (w->client->vsm_lookup_zone_by_terminal_id(terminal, &id) != VSMCLIENT_SUCCESS) - return NULL; - w->client->vsm_lookup_zone_by_id(id, &zone); - return wrap_vsm_zone(w, zone); -} - -API void vsm_array_string_free(VsmArrayString astring) -{ - if (!astring) { - return; - } - for (char** ptr = astring; *ptr; ++ptr) { - vsm_string_free(*ptr); - } - free(astring); -} - -API void vsm_string_free(VsmString string) -{ - free(string); -} - -API int vsm_add_event_callback(vsm_context_h, vsm_zone_event_cb, void*) { - LOGS(""); - return 0; -} -API int vsm_del_event_callback(vsm_context_h, int) { - LOGS(""); - return 0; -} -API int vsm_add_state_callback(vsm_context_h , vsm_zone_state_cb , void *) { - LOGS(""); - return 0; -} -API int vsm_del_state_callback(vsm_context_h , int ) { - LOGS(""); - return 0; -} -API int vsm_down_netdev(vsm_netdev_h) { - LOGS(""); - return 0; -} -API vsm_zone* vsm_get_foreground(vsm_context_h ctx) { - LOGS(""); - //return ((struct vasum_ops *)(ctx->vsm_ops))->get_foreground(ctx); - return dummy_ops.get_foreground(ctx); -} -API int vsm_get_host_pid(vsm_zone_h, pid_t) { - LOGS(""); - return 0; -} -API int vsm_get_ip_addr_netdev(vsm_netdev_h, vsm_netdev_addr_t, char*, int) { - LOGS(""); - return 0; -} -API void* vsm_get_userdata(vsm_zone_h) { - LOGS(""); - return NULL; -} -API int vsm_get_zone_id(vsm_zone_h zone) { - LOGS(""); - if (zone == NULL) - return -VSM_ERROR_INVALID; - return zone->id; -} -API vsm_zone_state_t vsm_get_zone_state(vsm_zone_h zone) { - LOGS(""); - if (zone == NULL) - return static_cast(-VSM_ERROR_INVALID); - return zone->state; -} -API int vsm_get_zone_terminal(vsm_zone_h) { - LOGS(""); - return -VSM_ERROR_NOT_SUPPORTED; -} -API const char *vsm_get_zone_type(vsm_zone_h zone) { - LOGS(""); - return zone == NULL ? NULL : zone->type; -} -API int vsm_is_equivalent_zone(vsm_context_h, pid_t) { - LOGS(""); - return 0; -} -API int vsm_is_virtualized() { - LOGS(""); - return 0; /* Running in Host */ -} -// libs/network.c -API int vsm_set_ip_addr_netdev(vsm_netdev_h, vsm_netdev_addr_t, const char*, int) { - LOGS(""); - return 0; -} -API int vsm_up_netdev(vsm_netdev_h) { - LOGS(""); - return 0; -} -// libs/zone.c -API int vsm_set_userdata(vsm_zone_h, void*) { - LOGS(""); - return 0; -} -API int vsm_state_change_watch_callback(struct vsm_context * /*ctx*/, char * /*name*/, - int /*state*/, int /*event*/) { - LOGS(""); - return 0; -} -// libs/vsm_signal.c -API int vsm_signal_state_broadcast(struct mxe_engine * /*engine*/, const char * /*zone_name*/, int /*state*/) { - LOGS(""); - return 0; -} -API int vsm_signal_event_broadcast(struct mxe_engine * /*engine*/, const char * /*zone_name*/, int /*event*/) { - LOGS(""); - return 0; -} -} // extern "C" -- 2.7.4