2 * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
4 * Contact: Jan Olszak (j.olszak@samsung.com)
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License
21 * @author Jan Olszak (j.olszak@samsung.com)
22 * @brief Server class definition
28 #include "exception.hpp"
30 #include "config/manager.hpp"
31 #include "logger/logger.hpp"
32 #include "utils/environment.hpp"
33 #include "utils/fs.hpp"
34 #include "utils/signal.hpp"
35 #include "utils/exception.hpp"
46 #include <boost/filesystem.hpp>
47 #include <linux/capability.h>
49 #include <sys/types.h>
52 #include <sys/utsname.h>
53 #include <lxc/lxccontainer.h>
54 #include <lxc/version.h>
58 #error "VASUM_USER must be defined!"
61 #ifndef INPUT_EVENT_GROUP
62 #error "INPUT_EVENT_GROUP must be defined!"
66 #error "DISK_GROUP must be defined!"
70 #error "TTY_GROUP must be defined!"
73 extern char** environ;
75 using namespace utils;
79 Server::Server(const std::string& configPath)
82 mConfigPath(configPath),
83 mSignalFD(mEventPoll),
84 mZonesManager(mEventPoll, mConfigPath),
85 mDispatchingThread(::pthread_self())
87 mSignalFD.setHandler(SIGUSR1, std::bind(&Server::handleUpdate, this));
88 mSignalFD.setHandler(SIGINT, std::bind(&Server::handleStop, this));
89 mSignalFD.setHandler(SIGTERM, std::bind(&Server::handleStop, this));
92 void Server::handleUpdate()
94 LOGD("Received SIGUSR1 - triggering update.");
95 mZonesManager.setZonesDetachOnExit();
96 mZonesManager.stop(false);
101 void Server::handleStop()
103 LOGD("Stopping Server");
104 mZonesManager.stop(false);
108 void Server::run(bool asRoot)
110 if (!prepareEnvironment(mConfigPath, asRoot)) {
111 throw ServerException("Environment setup failed");
114 mZonesManager.start();
116 while(mIsRunning || mZonesManager.isRunning()) {
117 mEventPoll.dispatchIteration(-1);
121 void Server::reloadIfRequired(char* argv[])
124 ::execve(argv[0], argv, environ);
125 LOGE("Failed to reload " << argv[0] << ": " << getSystemErrorMessage());
129 void Server::terminate()
131 LOGI("Terminating server");
132 int ret = ::pthread_kill(mDispatchingThread, SIGINT);
134 const std::string msg = "Error during Server termination: " + utils::getSystemErrorMessage(ret);
136 throw ServerException(msg);
140 bool Server::checkEnvironment()
144 int version, major, minor;
146 version = major = minor = 0;
147 ::sscanf(u.release, "%d.%d.%d", &version, &major, &minor);
148 if (version < 2 || (version == 2 && major < 6) || (version == 2 && major == 6 && minor < 29)) {
149 // control-group functionality was merged into kernel version 2.6.24 in 2007 (wikipedia)
150 // namespace support begins from kernels 2.4.19(mnt), 2.6.19(ns,uts,ipc), 2.6.24(pid), 2.6.29(net)
151 // namespace for usr from kernel 3.8(usr) - not used by vasum
152 std::cout << "kernel is old ver=" << u.release << ", run vasum-check-config" << std::endl;
156 std::cout << "kernel " << u.release << " [OK]" << std::endl;
158 // check lxc (TODO check if running on broken ABI version)
159 if (::strcmp(lxc_get_version(), LXC_VERSION)!=0) {
160 // versions that matters:
161 // 1.1.0 added function ptr 'in-the-middle' destroy_with_snapshots, snapshot_destroy_all (breaks ABI)
162 // 1.1.2 added function ptr 'append' attach_interface,detach_interface,checkpoint,restore (safe for ABI)
163 std::cout << "LXC version not match, compiled for " << LXC_VERSION << ", installed " << lxc_get_version() << std::endl;
167 std::cout << "LXC version " << lxc_get_version() << " [OK]" << std::endl;
169 // check cgroups (and its subsystems?)
170 std::string cgroupCheck = "/sys/fs/cgroup";
171 int fd = ::open(cgroupCheck.c_str(), O_RDONLY);
173 std::cout << "no cgroups support (can't access " << cgroupCheck << "), run vasum-check-config" << std::endl;
178 std::vector<std::string> cgroupSubsCheck = {"cpu", "cpuset", "memory"};
179 for (std::string f : cgroupSubsCheck) {
180 if (::faccessat(fd, f.c_str(), R_OK|X_OK, 0) == -1) {
181 std::cout << "no cgroups support (can't access " << cgroupCheck << "/" << f << ")" << std::endl;
187 std::cout << "cgroups problem, run vasum-check-config" << std::endl;
191 std::cout << "cgroups support " << " [OK]" << std::endl;
194 std::string nsCheck = "/proc/self/ns";
195 if (::access(nsCheck.c_str(), R_OK|X_OK) == -1) {
196 std::cout << "no namespace support (can't access " << nsCheck << "), run vasum-check-config" << std::endl;
200 std::cout << "namespaces support " << " [OK]" << std::endl;
207 bool Server::prepareEnvironment(const std::string& configPath, bool runAsRoot)
209 namespace fs = boost::filesystem;
211 // TODO: currently this config is loaded twice: here and in ZonesManager
212 ZonesManagerConfig config;
213 config::loadFromJsonFile(configPath, config);
215 struct passwd* pwd = ::getpwnam(VASUM_USER);
217 LOGE("getpwnam failed to find user '" << VASUM_USER << "'");
220 uid_t uid = pwd->pw_uid;
221 gid_t gid = pwd->pw_gid;
222 LOGD("vasum UID = " << uid << ", GID = " << gid);
224 // create directory for dbus socket (if needed)
225 if (!config.runMountPointPrefix.empty()) {
226 if (!utils::createDir(config.runMountPointPrefix, uid, gid,
227 fs::perms::owner_all |
228 fs::perms::group_read | fs::perms::group_exe |
229 fs::perms::others_read | fs::perms::others_exe)) {
234 // Omit supplementaty group setup and root drop if the user is already switched.
235 // This situation will happen during daemon update triggered by SIGUSR1.
236 if (!runAsRoot && geteuid() == uid) {
240 // INPUT_EVENT_GROUP provides access to /dev/input/event* devices used by InputMonitor.
241 // DISK_GROUP provides access to /dev/loop* devices, needed when adding new zone to copy
243 if (!utils::setSuppGroups({INPUT_EVENT_GROUP, DISK_GROUP, TTY_GROUP})) {
247 // CAP_SYS_ADMIN allows to mount tmpfs' for dbus communication at the runtime.
248 // NOTE: CAP_MAC_OVERRIDE is temporary and must be removed when "smack namespace"
249 // is introduced. The capability is needed to allow modify SMACK labels of
250 // "/var/run/zones/<zone>/run" mount point.
251 // CAP_SYS_TTY_CONFIG is needed to activate virtual terminals through ioctl calls
252 // CAP_CHOWN is needed when creating new zone from image to set owner/group for each file,
253 // directory or symlink
254 // CAP_SETUID is needed to launch specific funtions as root (see environment.cpp)
255 return (runAsRoot || utils::dropRoot(uid, gid, {CAP_SYS_ADMIN,