lxcpp: provisioning implementation (part 1)
[platform/core/security/vasum.git] / libs / lxcpp / container-impl.cpp
1 /*
2  *  Copyright (C) 2015 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *  This library is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License version 2.1 as published by the Free Software Foundation.
7  *
8  *  This library is distributed in the hope that it will be useful,
9  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  *  Lesser General Public License for more details.
12  *
13  *  You should have received a copy of the GNU Lesser General Public
14  *  License along with this library; if not, write to the Free Software
15  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
16  */
17
18 /**
19  * @file
20  * @author  Mateusz Malicki (m.malicki2@samsung.com)
21  * @brief   ContainerImpl definition
22  */
23
24 #include "lxcpp/container-impl.hpp"
25 #include "lxcpp/exception.hpp"
26 #include "lxcpp/process.hpp"
27 #include "lxcpp/filesystem.hpp"
28 #include "lxcpp/capability.hpp"
29 #include "lxcpp/commands/attach.hpp"
30 #include "lxcpp/commands/console.hpp"
31 #include "lxcpp/commands/start.hpp"
32 #include "lxcpp/commands/stop.hpp"
33 #include "lxcpp/commands/prep-host-terminal.hpp"
34 #include "lxcpp/commands/provision.hpp"
35
36 #include "logger/logger.hpp"
37 #include "utils/exception.hpp"
38
39 #include <unistd.h>
40 #include <sys/mount.h>
41 #include <sys/wait.h>
42 #include <mutex>
43 #include <algorithm>
44
45 #include <ext/stdio_filebuf.h>
46 #include <fstream>
47 #include <iostream>
48 #include <stdio.h>
49
50
51 namespace lxcpp {
52
53 ContainerImpl::ContainerImpl(const std::string &name, const std::string &path)
54 {
55     if (name.empty()) {
56         const std::string msg = "Name cannot be empty";
57         LOGE(msg);
58         throw ConfigureException(msg);
59     }
60
61     if (path.empty()) {
62         const std::string msg = "Path cannot be empty";
63         LOGE(msg);
64         throw ConfigureException(msg);
65     }
66
67     if(::access(path.c_str(), X_OK) < 0) {
68         const std::string msg = "Path must point to a traversable directory";
69         LOGE(msg);
70         throw ConfigureException(msg);
71     }
72
73     mConfig.mName = name;
74     mConfig.mRootPath = path;
75 }
76
77 // TODO: the aim of this constructor is to create a new ContainerImpl based on an already
78 // running container. It should talk to its guard and receive its current config.
79 ContainerImpl::ContainerImpl(pid_t /*guardPid*/)
80 {
81     throw NotImplementedException();
82 }
83
84 ContainerImpl::~ContainerImpl()
85 {
86 }
87
88 const std::string& ContainerImpl::getName() const
89 {
90     return mConfig.mName;
91 }
92
93 const std::string& ContainerImpl::getRootPath() const
94 {
95     return mConfig.mRootPath;
96 }
97
98 const std::vector<std::string>& ContainerImpl::getInit()
99 {
100     return mConfig.mInit;
101 }
102
103 void ContainerImpl::setInit(const std::vector<std::string> &init)
104 {
105     if (init.empty() || init[0].empty()) {
106         const std::string msg = "Init path cannot be empty";
107         LOGE(msg);
108         throw ConfigureException(msg);
109     }
110
111     std::string path = mConfig.mRootPath + "/" + init[0];
112
113     if (::access(path.c_str(), X_OK) < 0) {
114         const std::string msg = "Init path must point to an executable file";
115         LOGE(msg);
116         throw ConfigureException(msg);
117     }
118
119     mConfig.mInit = init;
120 }
121
122 pid_t ContainerImpl::getGuardPid() const
123 {
124     return mConfig.mGuardPid;
125 }
126
127 pid_t ContainerImpl::getInitPid() const
128 {
129     return mConfig.mInitPid;
130 }
131
132 void ContainerImpl::setLogger(const logger::LogType type,
133                               const logger::LogLevel level,
134                               const std::string &arg)
135 {
136     mConfig.mLogger.set(type, level, arg);
137 }
138
139 void ContainerImpl::setTerminalCount(const unsigned int count)
140 {
141     if (count == 0) {
142         const std::string msg = "Container needs at least one terminal";
143         LOGE(msg);
144         throw ConfigureException(msg);
145     }
146
147     mConfig.mTerminals.count = count;
148 }
149
150 void ContainerImpl::setNamespaces(const int namespaces)
151 {
152     mConfig.mNamespaces = namespaces;
153 }
154
155
156 int ContainerImpl::getNamespaces() const
157 {
158     return mConfig.mNamespaces;
159 }
160
161 void ContainerImpl::start()
162 {
163     // TODO: check config consistency and completeness somehow
164
165     PrepHostTerminal terminal(mConfig.mTerminals);
166     terminal.execute();
167
168     Start start(mConfig);
169     start.execute();
170 }
171
172 void ContainerImpl::stop()
173 {
174     // TODO: things to do when shutting down the container:
175     // - close PTY master FDs from the config so we won't keep PTYs open
176
177     Stop stop(mConfig);
178     stop.execute();
179 }
180
181 void ContainerImpl::freeze()
182 {
183     throw NotImplementedException();
184 }
185
186 void ContainerImpl::unfreeze()
187 {
188     throw NotImplementedException();
189 }
190
191 void ContainerImpl::reboot()
192 {
193     throw NotImplementedException();
194 }
195
196 void ContainerImpl::attach(const std::vector<std::string>& argv,
197                            const std::string& cwdInContainer)
198 {
199     Attach attach(*this,
200                   argv,
201                   /*uid in container*/ 0,
202                   /*gid in container*/ 0,
203                   "/dev/tty",
204                   /*supplementary gids in container*/ {},
205                   /*capsToKeep*/ 0,
206                   cwdInContainer,
207                   /*envToKeep*/ {},
208     /*envInContainer*/ {{"container","lxcpp"}});
209     // TODO: Env variables should agree with the ones already in the container
210     attach.execute();
211 }
212
213 void ContainerImpl::console()
214 {
215     Console console(mConfig.mTerminals);
216     console.execute();
217 }
218
219 bool ContainerImpl::isRunning() const
220 {
221     // TODO: race condition may occur, sync needed
222     return getInitPid() != -1;
223 }
224
225 void ContainerImpl::addInterfaceConfig(const std::string& hostif,
226                                        const std::string& zoneif,
227                                        InterfaceType type,
228                                        const std::vector<InetAddr>& addrs,
229                                        MacVLanMode mode)
230 {
231     mConfig.mNetwork.addInterfaceConfig(hostif, zoneif, type, addrs, mode);
232 }
233
234 void ContainerImpl::addInetConfig(const std::string& ifname, const InetAddr& addr)
235 {
236     mConfig.mNetwork.addInetConfig(ifname, addr);
237 }
238
239 std::vector<std::string> ContainerImpl::getInterfaces() const
240 {
241     return NetworkInterface::getInterfaces(getInitPid());
242 }
243
244 NetworkInterfaceInfo ContainerImpl::getInterfaceInfo(const std::string& ifname) const
245 {
246     NetworkInterface ni(ifname, getInitPid());
247     std::vector<InetAddr> addrs;
248     std::string macaddr;
249     int mtu = 0, flags = 0;
250     const Attrs& attrs = ni.getAttrs();
251     for (const Attr& a : attrs) {
252         switch (a.name) {
253         case AttrName::MAC:
254             macaddr = a.value;
255             break;
256         case AttrName::MTU:
257             mtu = std::stoul(a.value);
258             break;
259         case AttrName::FLAGS:
260             flags = std::stoul(a.value);
261             break;
262         default: //ignore others
263             break;
264         }
265     }
266     addrs = ni.getInetAddressList();
267     return NetworkInterfaceInfo{ifname, ni.status(), macaddr, mtu, flags, addrs};
268 }
269
270 void ContainerImpl::createInterface(const std::string& hostif,
271                                     const std::string& zoneif,
272                                     InterfaceType type,
273                                     MacVLanMode mode)
274 {
275     NetworkInterface ni(zoneif, getInitPid());
276     ni.create(type, hostif, mode);
277 }
278
279 void ContainerImpl::destroyInterface(const std::string& ifname)
280 {
281     NetworkInterface ni(ifname, getInitPid());
282     ni.destroy();
283 }
284
285 void ContainerImpl::moveInterface(const std::string& ifname)
286 {
287     NetworkInterface ni(ifname);
288     ni.moveToContainer(getInitPid());
289 }
290
291 void ContainerImpl::setUp(const std::string& ifname)
292 {
293     NetworkInterface ni(ifname, getInitPid());
294     ni.up();
295 }
296
297 void ContainerImpl::setDown(const std::string& ifname)
298 {
299     NetworkInterface ni(ifname, getInitPid());
300     ni.down();
301 }
302
303 void ContainerImpl::addInetAddr(const std::string& ifname, const InetAddr& addr)
304 {
305     NetworkInterface ni(ifname, getInitPid());
306     ni.addInetAddr(addr);
307 }
308
309 void ContainerImpl::delInetAddr(const std::string& ifname, const InetAddr& addr)
310 {
311     NetworkInterface ni(ifname, getInitPid());
312     ni.delInetAddr(addr);
313 }
314
315 void ContainerImpl::declareFile(const provision::File::Type type,
316                                 const std::string& path,
317                                 const int32_t flags,
318                                 const int32_t mode)
319 {
320     provision::File newFile({type, path, flags, mode});
321     mConfig.mProvisions.addFile(newFile);
322     // TODO: update guard config
323
324     if (isRunning()) {
325         ProvisionFile fileCmd(mConfig, newFile);
326         fileCmd.execute();
327     }
328 }
329
330 const FileVector& ContainerImpl::getFiles() const
331 {
332     return mConfig.mProvisions.getFiles();
333 }
334
335 void ContainerImpl::removeFile(const provision::File& item)
336 {
337     mConfig.mProvisions.removeFile(item);
338
339     if (isRunning()) {
340         ProvisionFile fileCmd(mConfig, item);
341         fileCmd.revert();
342     }
343 }
344
345 void ContainerImpl::declareMount(const std::string& source,
346                                  const std::string& target,
347                                  const std::string& type,
348                                  const int64_t flags,
349                                  const std::string& data)
350 {
351     provision::Mount newMount({source, target, type, flags, data});
352     mConfig.mProvisions.addMount(newMount);
353     // TODO: update guard config
354
355     if (isRunning()) {
356         ProvisionMount mountCmd(mConfig, newMount);
357         mountCmd.execute();
358     }
359 }
360
361 const MountVector& ContainerImpl::getMounts() const
362 {
363     return mConfig.mProvisions.getMounts();
364 }
365
366 void ContainerImpl::removeMount(const provision::Mount& item)
367 {
368     mConfig.mProvisions.removeMount(item);
369
370     if (isRunning()) {
371         ProvisionMount mountCmd(mConfig, item);
372         mountCmd.revert();
373     }
374 }
375
376 void ContainerImpl::declareLink(const std::string& source,
377                                 const std::string& target)
378 {
379     provision::Link newLink({source, target});
380     mConfig.mProvisions.addLink(newLink);
381     // TODO: update guard config
382
383     if (isRunning()) {
384         ProvisionLink linkCmd(mConfig, newLink);
385         linkCmd.execute();
386     }
387 }
388
389 const LinkVector& ContainerImpl::getLinks() const
390 {
391     return mConfig.mProvisions.getLinks();
392 }
393
394 void ContainerImpl::removeLink(const provision::Link& item)
395 {
396     mConfig.mProvisions.removeLink(item);
397
398     if (isRunning()) {
399         ProvisionLink linkCmd(mConfig, item);
400         linkCmd.revert();
401     }
402 }
403
404 } // namespace lxcpp