Merge lp:~ubuntu-branches/ubuntu/quantal/lxc/quantal-201209142015 into lp:ubuntu/quantal/lxc
- Quantal (12.10)
- quantal-201209142015
- Merge into quantal
Status: | Rejected |
---|---|
Rejected by: | James Westby |
Proposed branch: | lp:~ubuntu-branches/ubuntu/quantal/lxc/quantal-201209142015 |
Merge into: | lp:ubuntu/quantal/lxc |
Diff against target: |
5346 lines (+5305/-0) (has conflicts) 6 files modified
.pc/0220-getitem-per-hook-type/src/lxc/conf.c (+2522/-0) .pc/0220-getitem-per-hook-type/src/lxc/conf.h (+262/-0) .pc/0220-getitem-per-hook-type/src/lxc/confile.c (+1673/-0) .pc/0221-make-nonflush-upgrades-robust/templates/lxc-ubuntu.in (+713/-0) debian/patches/0220-getitem-per-hook-type (+84/-0) debian/patches/0221-make-nonflush-upgrades-robust (+51/-0) Conflict adding file .pc/0220-getitem-per-hook-type. Moved existing file to .pc/0220-getitem-per-hook-type.moved. Conflict adding file .pc/0221-make-nonflush-upgrades-robust. Moved existing file to .pc/0221-make-nonflush-upgrades-robust.moved. Conflict adding file debian/patches/0220-getitem-per-hook-type. Moved existing file to debian/patches/0220-getitem-per-hook-type.moved. Conflict adding file debian/patches/0221-make-nonflush-upgrades-robust. Moved existing file to debian/patches/0221-make-nonflush-upgrades-robust.moved. |
To merge this branch: | bzr merge lp:~ubuntu-branches/ubuntu/quantal/lxc/quantal-201209142015 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu branches | Pending | ||
Review via email: mp+124511@code.launchpad.net |
Commit message
Description of the change
The package importer has detected a possible inconsistency between the package history in the archive and the history in bzr. As the archive is authoritative the importer has made lp:ubuntu/quantal/lxc reflect what is in the archive and the old bzr branch has been pushed to lp:~ubuntu-branches/ubuntu/quantal/lxc/quantal-201209142015. This merge proposal was created so that an Ubuntu developer can review the situations and perform a merge/upload if necessary. There are three typical cases where this can happen.
1. Where someone pushes a change to bzr and someone else uploads the package without that change. This is the reason that this check is done by the importer. If this appears to be the case then a merge/upload should be done if the changes that were in bzr are still desirable.
2. The importer incorrectly detected the above situation when someone made a change in bzr and then uploaded it.
3. The importer incorrectly detected the above situation when someone just uploaded a package and didn't touch bzr.
If this case doesn't appear to be the first situation then set the status of the merge proposal to "Rejected" and help avoid the problem in future by filing a bug at https:/
(this is an automatically generated message)
Unmerged revisions
- 167. By Serge Hallyn
-
add DEP5 tags to 0220. Release.
- 166. By Serge Hallyn
-
add ; after 'false'
- 165. By Serge Hallyn
-
undo the fedora update.
- 164. By Serge Hallyn
-
0222-update-
fedora- template: update the download links in the fedora
template (LP: #1005951) - 163. By Serge Hallyn
-
0221-make-
nonflush- upgrades- robust: be more robust about out of date
container caches. (LP: #942862) - 162. By Serge Hallyn
-
fix off by one in check for subhook.
- 161. By Serge Hallyn
-
update a caller of lxc_clear_hooks() which i missed before.
- 160. By Serge Hallyn
-
0220-getitem-
per-hook- type: support clear_item for specific hooks.
(LP: #1050719)
Preview Diff
1 | === added directory '.pc/0220-getitem-per-hook-type' |
2 | === renamed directory '.pc/0220-getitem-per-hook-type' => '.pc/0220-getitem-per-hook-type.moved' |
3 | === added file '.pc/0220-getitem-per-hook-type/.timestamp' |
4 | === added directory '.pc/0220-getitem-per-hook-type/src' |
5 | === added directory '.pc/0220-getitem-per-hook-type/src/lxc' |
6 | === added file '.pc/0220-getitem-per-hook-type/src/lxc/conf.c' |
7 | --- .pc/0220-getitem-per-hook-type/src/lxc/conf.c 1970-01-01 00:00:00 +0000 |
8 | +++ .pc/0220-getitem-per-hook-type/src/lxc/conf.c 2012-09-14 20:24:18 +0000 |
9 | @@ -0,0 +1,2522 @@ |
10 | +/* |
11 | + * lxc: linux Container library |
12 | + * |
13 | + * (C) Copyright IBM Corp. 2007, 2008 |
14 | + * |
15 | + * Authors: |
16 | + * Daniel Lezcano <dlezcano at fr.ibm.com> |
17 | + * |
18 | + * This library is free software; you can redistribute it and/or |
19 | + * modify it under the terms of the GNU Lesser General Public |
20 | + * License as published by the Free Software Foundation; either |
21 | + * version 2.1 of the License, or (at your option) any later version. |
22 | + * |
23 | + * This library is distributed in the hope that it will be useful, |
24 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
25 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
26 | + * Lesser General Public License for more details. |
27 | + * |
28 | + * You should have received a copy of the GNU Lesser General Public |
29 | + * License along with this library; if not, write to the Free Software |
30 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
31 | + */ |
32 | +#define _GNU_SOURCE |
33 | +#include <stdio.h> |
34 | +#undef _GNU_SOURCE |
35 | +#include <stdlib.h> |
36 | +#include <stdarg.h> |
37 | +#include <errno.h> |
38 | +#include <string.h> |
39 | +#include <dirent.h> |
40 | +#include <mntent.h> |
41 | +#include <unistd.h> |
42 | +#include <sys/wait.h> |
43 | +#include <pty.h> |
44 | + |
45 | +#include <linux/loop.h> |
46 | + |
47 | +#include <sys/types.h> |
48 | +#include <sys/utsname.h> |
49 | +#include <sys/param.h> |
50 | +#include <sys/stat.h> |
51 | +#include <sys/socket.h> |
52 | +#include <sys/mount.h> |
53 | +#include <sys/mman.h> |
54 | +#include <sys/prctl.h> |
55 | +#include <sys/capability.h> |
56 | +#include <sys/personality.h> |
57 | + |
58 | +#include <arpa/inet.h> |
59 | +#include <fcntl.h> |
60 | +#include <netinet/in.h> |
61 | +#include <net/if.h> |
62 | +#include <libgen.h> |
63 | + |
64 | +#include "network.h" |
65 | +#include "error.h" |
66 | +#include "parse.h" |
67 | +#include "config.h" |
68 | +#include "utils.h" |
69 | +#include "conf.h" |
70 | +#include "log.h" |
71 | +#include "lxc.h" /* for lxc_cgroup_set() */ |
72 | +#include "caps.h" /* for lxc_caps_last_cap() */ |
73 | + |
74 | +lxc_log_define(lxc_conf, lxc); |
75 | + |
76 | +#define MAXHWLEN 18 |
77 | +#define MAXINDEXLEN 20 |
78 | +#define MAXMTULEN 16 |
79 | +#define MAXLINELEN 128 |
80 | + |
81 | +#ifndef MS_DIRSYNC |
82 | +#define MS_DIRSYNC 128 |
83 | +#endif |
84 | + |
85 | +#ifndef MS_REC |
86 | +#define MS_REC 16384 |
87 | +#endif |
88 | + |
89 | +#ifndef MNT_DETACH |
90 | +#define MNT_DETACH 2 |
91 | +#endif |
92 | + |
93 | +#ifndef MS_RELATIME |
94 | +#define MS_RELATIME (1 << 21) |
95 | +#endif |
96 | + |
97 | +#ifndef MS_STRICTATIME |
98 | +#define MS_STRICTATIME (1 << 24) |
99 | +#endif |
100 | + |
101 | +#ifndef CAP_SETFCAP |
102 | +#define CAP_SETFCAP 31 |
103 | +#endif |
104 | + |
105 | +#ifndef CAP_MAC_OVERRIDE |
106 | +#define CAP_MAC_OVERRIDE 32 |
107 | +#endif |
108 | + |
109 | +#ifndef CAP_MAC_ADMIN |
110 | +#define CAP_MAC_ADMIN 33 |
111 | +#endif |
112 | + |
113 | +#ifndef PR_CAPBSET_DROP |
114 | +#define PR_CAPBSET_DROP 24 |
115 | +#endif |
116 | + |
117 | +char *lxchook_names[NUM_LXC_HOOKS] = { |
118 | + "pre-start", "pre-mount", "mount", "start", "post-stop" }; |
119 | + |
120 | +extern int pivot_root(const char * new_root, const char * put_old); |
121 | + |
122 | +typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *); |
123 | + |
124 | +struct mount_opt { |
125 | + char *name; |
126 | + int clear; |
127 | + int flag; |
128 | +}; |
129 | + |
130 | +struct caps_opt { |
131 | + char *name; |
132 | + int value; |
133 | +}; |
134 | + |
135 | +static int instanciate_veth(struct lxc_handler *, struct lxc_netdev *); |
136 | +static int instanciate_macvlan(struct lxc_handler *, struct lxc_netdev *); |
137 | +static int instanciate_vlan(struct lxc_handler *, struct lxc_netdev *); |
138 | +static int instanciate_phys(struct lxc_handler *, struct lxc_netdev *); |
139 | +static int instanciate_empty(struct lxc_handler *, struct lxc_netdev *); |
140 | + |
141 | +static instanciate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = { |
142 | + [LXC_NET_VETH] = instanciate_veth, |
143 | + [LXC_NET_MACVLAN] = instanciate_macvlan, |
144 | + [LXC_NET_VLAN] = instanciate_vlan, |
145 | + [LXC_NET_PHYS] = instanciate_phys, |
146 | + [LXC_NET_EMPTY] = instanciate_empty, |
147 | +}; |
148 | + |
149 | +static struct mount_opt mount_opt[] = { |
150 | + { "defaults", 0, 0 }, |
151 | + { "ro", 0, MS_RDONLY }, |
152 | + { "rw", 1, MS_RDONLY }, |
153 | + { "suid", 1, MS_NOSUID }, |
154 | + { "nosuid", 0, MS_NOSUID }, |
155 | + { "dev", 1, MS_NODEV }, |
156 | + { "nodev", 0, MS_NODEV }, |
157 | + { "exec", 1, MS_NOEXEC }, |
158 | + { "noexec", 0, MS_NOEXEC }, |
159 | + { "sync", 0, MS_SYNCHRONOUS }, |
160 | + { "async", 1, MS_SYNCHRONOUS }, |
161 | + { "dirsync", 0, MS_DIRSYNC }, |
162 | + { "remount", 0, MS_REMOUNT }, |
163 | + { "mand", 0, MS_MANDLOCK }, |
164 | + { "nomand", 1, MS_MANDLOCK }, |
165 | + { "atime", 1, MS_NOATIME }, |
166 | + { "noatime", 0, MS_NOATIME }, |
167 | + { "diratime", 1, MS_NODIRATIME }, |
168 | + { "nodiratime", 0, MS_NODIRATIME }, |
169 | + { "bind", 0, MS_BIND }, |
170 | + { "rbind", 0, MS_BIND|MS_REC }, |
171 | + { "relatime", 0, MS_RELATIME }, |
172 | + { "norelatime", 1, MS_RELATIME }, |
173 | + { "strictatime", 0, MS_STRICTATIME }, |
174 | + { "nostrictatime", 1, MS_STRICTATIME }, |
175 | + { NULL, 0, 0 }, |
176 | +}; |
177 | + |
178 | +static struct caps_opt caps_opt[] = { |
179 | + { "chown", CAP_CHOWN }, |
180 | + { "dac_override", CAP_DAC_OVERRIDE }, |
181 | + { "dac_read_search", CAP_DAC_READ_SEARCH }, |
182 | + { "fowner", CAP_FOWNER }, |
183 | + { "fsetid", CAP_FSETID }, |
184 | + { "kill", CAP_KILL }, |
185 | + { "setgid", CAP_SETGID }, |
186 | + { "setuid", CAP_SETUID }, |
187 | + { "setpcap", CAP_SETPCAP }, |
188 | + { "linux_immutable", CAP_LINUX_IMMUTABLE }, |
189 | + { "net_bind_service", CAP_NET_BIND_SERVICE }, |
190 | + { "net_broadcast", CAP_NET_BROADCAST }, |
191 | + { "net_admin", CAP_NET_ADMIN }, |
192 | + { "net_raw", CAP_NET_RAW }, |
193 | + { "ipc_lock", CAP_IPC_LOCK }, |
194 | + { "ipc_owner", CAP_IPC_OWNER }, |
195 | + { "sys_module", CAP_SYS_MODULE }, |
196 | + { "sys_rawio", CAP_SYS_RAWIO }, |
197 | + { "sys_chroot", CAP_SYS_CHROOT }, |
198 | + { "sys_ptrace", CAP_SYS_PTRACE }, |
199 | + { "sys_pacct", CAP_SYS_PACCT }, |
200 | + { "sys_admin", CAP_SYS_ADMIN }, |
201 | + { "sys_boot", CAP_SYS_BOOT }, |
202 | + { "sys_nice", CAP_SYS_NICE }, |
203 | + { "sys_resource", CAP_SYS_RESOURCE }, |
204 | + { "sys_time", CAP_SYS_TIME }, |
205 | + { "sys_tty_config", CAP_SYS_TTY_CONFIG }, |
206 | + { "mknod", CAP_MKNOD }, |
207 | + { "lease", CAP_LEASE }, |
208 | +#ifdef CAP_AUDIT_WRITE |
209 | + { "audit_write", CAP_AUDIT_WRITE }, |
210 | +#endif |
211 | +#ifdef CAP_AUDIT_CONTROL |
212 | + { "audit_control", CAP_AUDIT_CONTROL }, |
213 | +#endif |
214 | + { "setfcap", CAP_SETFCAP }, |
215 | + { "mac_override", CAP_MAC_OVERRIDE }, |
216 | + { "mac_admin", CAP_MAC_ADMIN }, |
217 | +#ifdef CAP_SYSLOG |
218 | + { "syslog", CAP_SYSLOG }, |
219 | +#endif |
220 | +#ifdef CAP_WAKE_ALARM |
221 | + { "wake_alarm", CAP_WAKE_ALARM }, |
222 | +#endif |
223 | +}; |
224 | + |
225 | +static int run_script(const char *name, const char *section, |
226 | + const char *script, ...) |
227 | +{ |
228 | + int ret; |
229 | + FILE *f; |
230 | + char *buffer, *p, *output; |
231 | + size_t size = 0; |
232 | + va_list ap; |
233 | + |
234 | + INFO("Executing script '%s' for container '%s', config section '%s'", |
235 | + script, name, section); |
236 | + |
237 | + va_start(ap, script); |
238 | + while ((p = va_arg(ap, char *))) |
239 | + size += strlen(p) + 1; |
240 | + va_end(ap); |
241 | + |
242 | + size += strlen(script); |
243 | + size += strlen(name); |
244 | + size += strlen(section); |
245 | + size += 3; |
246 | + |
247 | + if (size > INT_MAX) |
248 | + return -1; |
249 | + |
250 | + buffer = alloca(size); |
251 | + if (!buffer) { |
252 | + ERROR("failed to allocate memory"); |
253 | + return -1; |
254 | + } |
255 | + |
256 | + ret = snprintf(buffer, size, "%s %s %s", script, name, section); |
257 | + if (ret < 0 || ret >= size) { |
258 | + ERROR("Script name too long"); |
259 | + free(buffer); |
260 | + return -1; |
261 | + } |
262 | + |
263 | + va_start(ap, script); |
264 | + while ((p = va_arg(ap, char *))) { |
265 | + int len = size-ret; |
266 | + int rc; |
267 | + rc = snprintf(buffer + ret, len, " %s", p); |
268 | + if (rc < 0 || rc >= len) { |
269 | + free(buffer); |
270 | + ERROR("Script args too long"); |
271 | + return -1; |
272 | + } |
273 | + ret += rc; |
274 | + } |
275 | + va_end(ap); |
276 | + |
277 | + f = popen(buffer, "r"); |
278 | + if (!f) { |
279 | + SYSERROR("popen failed"); |
280 | + return -1; |
281 | + } |
282 | + |
283 | + output = malloc(LXC_LOG_BUFFER_SIZE); |
284 | + if (!output) { |
285 | + ERROR("failed to allocate memory for script output"); |
286 | + return -1; |
287 | + } |
288 | + |
289 | + while(fgets(output, LXC_LOG_BUFFER_SIZE, f)) |
290 | + DEBUG("script output: %s", output); |
291 | + |
292 | + free(output); |
293 | + |
294 | + if (pclose(f) == -1) { |
295 | + SYSERROR("Script exited on error"); |
296 | + return -1; |
297 | + } |
298 | + |
299 | + return 0; |
300 | +} |
301 | + |
302 | +static int find_fstype_cb(char* buffer, void *data) |
303 | +{ |
304 | + struct cbarg { |
305 | + const char *rootfs; |
306 | + const char *target; |
307 | + int mntopt; |
308 | + } *cbarg = data; |
309 | + |
310 | + char *fstype; |
311 | + |
312 | + /* we don't try 'nodev' entries */ |
313 | + if (strstr(buffer, "nodev")) |
314 | + return 0; |
315 | + |
316 | + fstype = buffer; |
317 | + fstype += lxc_char_left_gc(fstype, strlen(fstype)); |
318 | + fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0'; |
319 | + |
320 | + DEBUG("trying to mount '%s'->'%s' with fstype '%s'", |
321 | + cbarg->rootfs, cbarg->target, fstype); |
322 | + |
323 | + if (mount(cbarg->rootfs, cbarg->target, fstype, cbarg->mntopt, NULL)) { |
324 | + DEBUG("mount failed with error: %s", strerror(errno)); |
325 | + return 0; |
326 | + } |
327 | + |
328 | + INFO("mounted '%s' on '%s', with fstype '%s'", |
329 | + cbarg->rootfs, cbarg->target, fstype); |
330 | + |
331 | + return 1; |
332 | +} |
333 | + |
334 | +static int mount_unknow_fs(const char *rootfs, const char *target, int mntopt) |
335 | +{ |
336 | + int i; |
337 | + |
338 | + struct cbarg { |
339 | + const char *rootfs; |
340 | + const char *target; |
341 | + int mntopt; |
342 | + } cbarg = { |
343 | + .rootfs = rootfs, |
344 | + .target = target, |
345 | + .mntopt = mntopt, |
346 | + }; |
347 | + |
348 | + /* |
349 | + * find the filesystem type with brute force: |
350 | + * first we check with /etc/filesystems, in case the modules |
351 | + * are auto-loaded and fall back to the supported kernel fs |
352 | + */ |
353 | + char *fsfile[] = { |
354 | + "/etc/filesystems", |
355 | + "/proc/filesystems", |
356 | + }; |
357 | + |
358 | + for (i = 0; i < sizeof(fsfile)/sizeof(fsfile[0]); i++) { |
359 | + |
360 | + int ret; |
361 | + |
362 | + if (access(fsfile[i], F_OK)) |
363 | + continue; |
364 | + |
365 | + ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg); |
366 | + if (ret < 0) { |
367 | + ERROR("failed to parse '%s'", fsfile[i]); |
368 | + return -1; |
369 | + } |
370 | + |
371 | + if (ret) |
372 | + return 0; |
373 | + } |
374 | + |
375 | + ERROR("failed to determine fs type for '%s'", rootfs); |
376 | + return -1; |
377 | +} |
378 | + |
379 | +static int mount_rootfs_dir(const char *rootfs, const char *target) |
380 | +{ |
381 | + return mount(rootfs, target, "none", MS_BIND | MS_REC, NULL); |
382 | +} |
383 | + |
384 | +static int setup_lodev(const char *rootfs, int fd, struct loop_info64 *loinfo) |
385 | +{ |
386 | + int rfd; |
387 | + int ret = -1; |
388 | + |
389 | + rfd = open(rootfs, O_RDWR); |
390 | + if (rfd < 0) { |
391 | + SYSERROR("failed to open '%s'", rootfs); |
392 | + return -1; |
393 | + } |
394 | + |
395 | + memset(loinfo, 0, sizeof(*loinfo)); |
396 | + |
397 | + loinfo->lo_flags = LO_FLAGS_AUTOCLEAR; |
398 | + |
399 | + if (ioctl(fd, LOOP_SET_FD, rfd)) { |
400 | + SYSERROR("failed to LOOP_SET_FD"); |
401 | + goto out; |
402 | + } |
403 | + |
404 | + if (ioctl(fd, LOOP_SET_STATUS64, loinfo)) { |
405 | + SYSERROR("failed to LOOP_SET_STATUS64"); |
406 | + goto out; |
407 | + } |
408 | + |
409 | + ret = 0; |
410 | +out: |
411 | + close(rfd); |
412 | + |
413 | + return ret; |
414 | +} |
415 | + |
416 | +static int mount_rootfs_file(const char *rootfs, const char *target) |
417 | +{ |
418 | + struct dirent dirent, *direntp; |
419 | + struct loop_info64 loinfo; |
420 | + int ret = -1, fd = -1, rc; |
421 | + DIR *dir; |
422 | + char path[MAXPATHLEN]; |
423 | + |
424 | + dir = opendir("/dev"); |
425 | + if (!dir) { |
426 | + SYSERROR("failed to open '/dev'"); |
427 | + return -1; |
428 | + } |
429 | + |
430 | + while (!readdir_r(dir, &dirent, &direntp)) { |
431 | + |
432 | + if (!direntp) |
433 | + break; |
434 | + |
435 | + if (!strcmp(direntp->d_name, ".")) |
436 | + continue; |
437 | + |
438 | + if (!strcmp(direntp->d_name, "..")) |
439 | + continue; |
440 | + |
441 | + if (strncmp(direntp->d_name, "loop", 4)) |
442 | + continue; |
443 | + |
444 | + rc = snprintf(path, MAXPATHLEN, "/dev/%s", direntp->d_name); |
445 | + if (rc < 0 || rc >= MAXPATHLEN) |
446 | + continue; |
447 | + |
448 | + fd = open(path, O_RDWR); |
449 | + if (fd < 0) |
450 | + continue; |
451 | + |
452 | + if (ioctl(fd, LOOP_GET_STATUS64, &loinfo) == 0) { |
453 | + close(fd); |
454 | + continue; |
455 | + } |
456 | + |
457 | + if (errno != ENXIO) { |
458 | + WARN("unexpected error for ioctl on '%s': %m", |
459 | + direntp->d_name); |
460 | + continue; |
461 | + } |
462 | + |
463 | + DEBUG("found '%s' free lodev", path); |
464 | + |
465 | + ret = setup_lodev(rootfs, fd, &loinfo); |
466 | + if (!ret) |
467 | + ret = mount_unknow_fs(path, target, 0); |
468 | + close(fd); |
469 | + |
470 | + break; |
471 | + } |
472 | + |
473 | + if (closedir(dir)) |
474 | + WARN("failed to close directory"); |
475 | + |
476 | + return ret; |
477 | +} |
478 | + |
479 | +static int mount_rootfs_block(const char *rootfs, const char *target) |
480 | +{ |
481 | + return mount_unknow_fs(rootfs, target, 0); |
482 | +} |
483 | + |
484 | +/* |
485 | + * pin_rootfs |
486 | + * if rootfs is a directory, then open ${rootfs}.hold for writing for the |
487 | + * duration of the container run, to prevent the container from marking the |
488 | + * underlying fs readonly on shutdown. |
489 | + * return -1 on error. |
490 | + * return -2 if nothing needed to be pinned. |
491 | + * return an open fd (>=0) if we pinned it. |
492 | + */ |
493 | +int pin_rootfs(const char *rootfs) |
494 | +{ |
495 | + char absrootfs[MAXPATHLEN]; |
496 | + char absrootfspin[MAXPATHLEN]; |
497 | + struct stat s; |
498 | + int ret, fd; |
499 | + |
500 | + if (rootfs == NULL || strlen(rootfs) == 0) |
501 | + return 0; |
502 | + |
503 | + if (!realpath(rootfs, absrootfs)) { |
504 | + SYSERROR("failed to get real path for '%s'", rootfs); |
505 | + return -1; |
506 | + } |
507 | + |
508 | + if (access(absrootfs, F_OK)) { |
509 | + SYSERROR("'%s' is not accessible", absrootfs); |
510 | + return -1; |
511 | + } |
512 | + |
513 | + if (stat(absrootfs, &s)) { |
514 | + SYSERROR("failed to stat '%s'", absrootfs); |
515 | + return -1; |
516 | + } |
517 | + |
518 | + if (!__S_ISTYPE(s.st_mode, S_IFDIR)) |
519 | + return -2; |
520 | + |
521 | + ret = snprintf(absrootfspin, MAXPATHLEN, "%s%s", absrootfs, ".hold"); |
522 | + if (ret >= MAXPATHLEN) { |
523 | + SYSERROR("pathname too long for rootfs hold file"); |
524 | + return -1; |
525 | + } |
526 | + |
527 | + fd = open(absrootfspin, O_CREAT | O_RDWR, S_IWUSR|S_IRUSR); |
528 | + INFO("opened %s as fd %d\n", absrootfspin, fd); |
529 | + return fd; |
530 | +} |
531 | + |
532 | +static int mount_rootfs(const char *rootfs, const char *target) |
533 | +{ |
534 | + char absrootfs[MAXPATHLEN]; |
535 | + struct stat s; |
536 | + int i; |
537 | + |
538 | + typedef int (*rootfs_cb)(const char *, const char *); |
539 | + |
540 | + struct rootfs_type { |
541 | + int type; |
542 | + rootfs_cb cb; |
543 | + } rtfs_type[] = { |
544 | + { S_IFDIR, mount_rootfs_dir }, |
545 | + { S_IFBLK, mount_rootfs_block }, |
546 | + { S_IFREG, mount_rootfs_file }, |
547 | + }; |
548 | + |
549 | + if (!realpath(rootfs, absrootfs)) { |
550 | + SYSERROR("failed to get real path for '%s'", rootfs); |
551 | + return -1; |
552 | + } |
553 | + |
554 | + if (access(absrootfs, F_OK)) { |
555 | + SYSERROR("'%s' is not accessible", absrootfs); |
556 | + return -1; |
557 | + } |
558 | + |
559 | + if (stat(absrootfs, &s)) { |
560 | + SYSERROR("failed to stat '%s'", absrootfs); |
561 | + return -1; |
562 | + } |
563 | + |
564 | + for (i = 0; i < sizeof(rtfs_type)/sizeof(rtfs_type[0]); i++) { |
565 | + |
566 | + if (!__S_ISTYPE(s.st_mode, rtfs_type[i].type)) |
567 | + continue; |
568 | + |
569 | + return rtfs_type[i].cb(absrootfs, target); |
570 | + } |
571 | + |
572 | + ERROR("unsupported rootfs type for '%s'", absrootfs); |
573 | + return -1; |
574 | +} |
575 | + |
576 | +static int setup_utsname(struct utsname *utsname) |
577 | +{ |
578 | + if (!utsname) |
579 | + return 0; |
580 | + |
581 | + if (sethostname(utsname->nodename, strlen(utsname->nodename))) { |
582 | + SYSERROR("failed to set the hostname to '%s'", utsname->nodename); |
583 | + return -1; |
584 | + } |
585 | + |
586 | + INFO("'%s' hostname has been setup", utsname->nodename); |
587 | + |
588 | + return 0; |
589 | +} |
590 | + |
591 | +static int setup_tty(const struct lxc_rootfs *rootfs, |
592 | + const struct lxc_tty_info *tty_info, char *ttydir) |
593 | +{ |
594 | + char path[MAXPATHLEN], lxcpath[MAXPATHLEN]; |
595 | + int i, ret; |
596 | + |
597 | + if (!rootfs->path) |
598 | + return 0; |
599 | + |
600 | + for (i = 0; i < tty_info->nbtty; i++) { |
601 | + |
602 | + struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; |
603 | + |
604 | + ret = snprintf(path, sizeof(path), "%s/dev/tty%d", |
605 | + rootfs->mount, i + 1); |
606 | + if (ret >= sizeof(path)) { |
607 | + ERROR("pathname too long for ttys"); |
608 | + return -1; |
609 | + } |
610 | + if (ttydir) { |
611 | + /* create dev/lxc/tty%d" */ |
612 | + ret = snprintf(lxcpath, sizeof(lxcpath), "%s/dev/%s/tty%d", |
613 | + rootfs->mount, ttydir, i + 1); |
614 | + if (ret >= sizeof(lxcpath)) { |
615 | + ERROR("pathname too long for ttys"); |
616 | + return -1; |
617 | + } |
618 | + ret = creat(lxcpath, 0660); |
619 | + if (ret==-1 && errno != EEXIST) { |
620 | + SYSERROR("error creating %s\n", lxcpath); |
621 | + return -1; |
622 | + } |
623 | + close(ret); |
624 | + ret = unlink(path); |
625 | + if (ret && errno != ENOENT) { |
626 | + SYSERROR("error unlinking %s\n", path); |
627 | + return -1; |
628 | + } |
629 | + |
630 | + if (mount(pty_info->name, lxcpath, "none", MS_BIND, 0)) { |
631 | + WARN("failed to mount '%s'->'%s'", |
632 | + pty_info->name, path); |
633 | + continue; |
634 | + } |
635 | + |
636 | + ret = snprintf(lxcpath, sizeof(lxcpath), "%s/tty%d", ttydir, i+1); |
637 | + if (ret >= sizeof(lxcpath)) { |
638 | + ERROR("tty pathname too long"); |
639 | + return -1; |
640 | + } |
641 | + ret = symlink(lxcpath, path); |
642 | + if (ret) { |
643 | + SYSERROR("failed to create symlink for tty %d\n", i+1); |
644 | + return -1; |
645 | + } |
646 | + } else { |
647 | + if (mount(pty_info->name, path, "none", MS_BIND, 0)) { |
648 | + WARN("failed to mount '%s'->'%s'", |
649 | + pty_info->name, path); |
650 | + continue; |
651 | + } |
652 | + } |
653 | + } |
654 | + |
655 | + INFO("%d tty(s) has been setup", tty_info->nbtty); |
656 | + |
657 | + return 0; |
658 | +} |
659 | + |
660 | +static int setup_rootfs_pivot_root_cb(char *buffer, void *data) |
661 | +{ |
662 | + struct lxc_list *mountlist, *listentry, *iterator; |
663 | + char *pivotdir, *mountpoint, *mountentry; |
664 | + int found; |
665 | + void **cbparm; |
666 | + |
667 | + mountentry = buffer; |
668 | + cbparm = (void **)data; |
669 | + |
670 | + mountlist = cbparm[0]; |
671 | + pivotdir = cbparm[1]; |
672 | + |
673 | + /* parse entry, first field is mountname, ignore */ |
674 | + mountpoint = strtok(mountentry, " "); |
675 | + if (!mountpoint) |
676 | + return -1; |
677 | + |
678 | + /* second field is mountpoint */ |
679 | + mountpoint = strtok(NULL, " "); |
680 | + if (!mountpoint) |
681 | + return -1; |
682 | + |
683 | + /* only consider mountpoints below old root fs */ |
684 | + if (strncmp(mountpoint, pivotdir, strlen(pivotdir))) |
685 | + return 0; |
686 | + |
687 | + /* filter duplicate mountpoints */ |
688 | + found = 0; |
689 | + lxc_list_for_each(iterator, mountlist) { |
690 | + if (!strcmp(iterator->elem, mountpoint)) { |
691 | + found = 1; |
692 | + break; |
693 | + } |
694 | + } |
695 | + if (found) |
696 | + return 0; |
697 | + |
698 | + /* add entry to list */ |
699 | + listentry = malloc(sizeof(*listentry)); |
700 | + if (!listentry) { |
701 | + SYSERROR("malloc for mountpoint listentry failed"); |
702 | + return -1; |
703 | + } |
704 | + |
705 | + listentry->elem = strdup(mountpoint); |
706 | + if (!listentry->elem) { |
707 | + SYSERROR("strdup failed"); |
708 | + return -1; |
709 | + } |
710 | + lxc_list_add_tail(mountlist, listentry); |
711 | + |
712 | + return 0; |
713 | +} |
714 | + |
715 | +static int umount_oldrootfs(const char *oldrootfs) |
716 | +{ |
717 | + char path[MAXPATHLEN]; |
718 | + void *cbparm[2]; |
719 | + struct lxc_list mountlist, *iterator; |
720 | + int ok, still_mounted, last_still_mounted; |
721 | + int rc; |
722 | + |
723 | + /* read and parse /proc/mounts in old root fs */ |
724 | + lxc_list_init(&mountlist); |
725 | + |
726 | + /* oldrootfs is on the top tree directory now */ |
727 | + rc = snprintf(path, sizeof(path), "/%s", oldrootfs); |
728 | + if (rc >= sizeof(path)) { |
729 | + ERROR("rootfs name too long"); |
730 | + return -1; |
731 | + } |
732 | + cbparm[0] = &mountlist; |
733 | + |
734 | + cbparm[1] = strdup(path); |
735 | + if (!cbparm[1]) { |
736 | + SYSERROR("strdup failed"); |
737 | + return -1; |
738 | + } |
739 | + |
740 | + rc = snprintf(path, sizeof(path), "%s/proc/mounts", oldrootfs); |
741 | + if (rc >= sizeof(path)) { |
742 | + ERROR("container proc/mounts name too long"); |
743 | + return -1; |
744 | + } |
745 | + |
746 | + ok = lxc_file_for_each_line(path, |
747 | + setup_rootfs_pivot_root_cb, &cbparm); |
748 | + if (ok < 0) { |
749 | + SYSERROR("failed to read or parse mount list '%s'", path); |
750 | + return -1; |
751 | + } |
752 | + |
753 | + /* umount filesystems until none left or list no longer shrinks */ |
754 | + still_mounted = 0; |
755 | + do { |
756 | + last_still_mounted = still_mounted; |
757 | + still_mounted = 0; |
758 | + |
759 | + lxc_list_for_each(iterator, &mountlist) { |
760 | + |
761 | + /* umount normally */ |
762 | + if (!umount(iterator->elem)) { |
763 | + DEBUG("umounted '%s'", (char *)iterator->elem); |
764 | + lxc_list_del(iterator); |
765 | + continue; |
766 | + } |
767 | + |
768 | + still_mounted++; |
769 | + } |
770 | + |
771 | + } while (still_mounted > 0 && still_mounted != last_still_mounted); |
772 | + |
773 | + |
774 | + lxc_list_for_each(iterator, &mountlist) { |
775 | + |
776 | + /* let's try a lazy umount */ |
777 | + if (!umount2(iterator->elem, MNT_DETACH)) { |
778 | + INFO("lazy unmount of '%s'", (char *)iterator->elem); |
779 | + continue; |
780 | + } |
781 | + |
782 | + /* be more brutal (nfs) */ |
783 | + if (!umount2(iterator->elem, MNT_FORCE)) { |
784 | + INFO("forced unmount of '%s'", (char *)iterator->elem); |
785 | + continue; |
786 | + } |
787 | + |
788 | + WARN("failed to unmount '%s'", (char *)iterator->elem); |
789 | + } |
790 | + |
791 | + return 0; |
792 | +} |
793 | + |
794 | +static int setup_rootfs_pivot_root(const char *rootfs, const char *pivotdir) |
795 | +{ |
796 | + char path[MAXPATHLEN]; |
797 | + int remove_pivotdir = 0; |
798 | + int rc; |
799 | + |
800 | + /* change into new root fs */ |
801 | + if (chdir(rootfs)) { |
802 | + SYSERROR("can't chdir to new rootfs '%s'", rootfs); |
803 | + return -1; |
804 | + } |
805 | + |
806 | + if (!pivotdir) |
807 | + pivotdir = "mnt"; |
808 | + |
809 | + /* compute the full path to pivotdir under rootfs */ |
810 | + rc = snprintf(path, sizeof(path), "%s/%s", rootfs, pivotdir); |
811 | + if (rc >= sizeof(path)) { |
812 | + ERROR("pivot dir name too long"); |
813 | + return -1; |
814 | + } |
815 | + |
816 | + if (access(path, F_OK)) { |
817 | + |
818 | + if (mkdir_p(path, 0755)) { |
819 | + SYSERROR("failed to create pivotdir '%s'", path); |
820 | + return -1; |
821 | + } |
822 | + |
823 | + remove_pivotdir = 1; |
824 | + DEBUG("created '%s' directory", path); |
825 | + } |
826 | + |
827 | + DEBUG("mountpoint for old rootfs is '%s'", path); |
828 | + |
829 | + /* pivot_root into our new root fs */ |
830 | + if (pivot_root(".", path)) { |
831 | + SYSERROR("pivot_root syscall failed"); |
832 | + return -1; |
833 | + } |
834 | + |
835 | + if (chdir("/")) { |
836 | + SYSERROR("can't chdir to / after pivot_root"); |
837 | + return -1; |
838 | + } |
839 | + |
840 | + DEBUG("pivot_root syscall to '%s' successful", rootfs); |
841 | + |
842 | + /* we switch from absolute path to relative path */ |
843 | + if (umount_oldrootfs(pivotdir)) |
844 | + return -1; |
845 | + |
846 | + /* remove temporary mount point, we don't consider the removing |
847 | + * as fatal */ |
848 | + if (remove_pivotdir && rmdir(pivotdir)) |
849 | + WARN("can't remove mountpoint '%s': %m", pivotdir); |
850 | + |
851 | + return 0; |
852 | +} |
853 | + |
854 | +static int setup_rootfs(const struct lxc_rootfs *rootfs) |
855 | +{ |
856 | + if (!rootfs->path) |
857 | + return 0; |
858 | + |
859 | + if (access(rootfs->mount, F_OK)) { |
860 | + SYSERROR("failed to access to '%s', check it is present", |
861 | + rootfs->mount); |
862 | + return -1; |
863 | + } |
864 | + |
865 | + if (mount_rootfs(rootfs->path, rootfs->mount)) { |
866 | + ERROR("failed to mount rootfs"); |
867 | + return -1; |
868 | + } |
869 | + |
870 | + DEBUG("mounted '%s' on '%s'", rootfs->path, rootfs->mount); |
871 | + |
872 | + return 0; |
873 | +} |
874 | + |
875 | +int setup_pivot_root(const struct lxc_rootfs *rootfs) |
876 | +{ |
877 | + if (!rootfs->path) |
878 | + return 0; |
879 | + |
880 | + if (setup_rootfs_pivot_root(rootfs->mount, rootfs->pivot)) { |
881 | + ERROR("failed to setup pivot root"); |
882 | + return -1; |
883 | + } |
884 | + |
885 | + return 0; |
886 | +} |
887 | + |
888 | +static int setup_pts(int pts) |
889 | +{ |
890 | + char target[PATH_MAX]; |
891 | + |
892 | + if (!pts) |
893 | + return 0; |
894 | + |
895 | + if (!access("/dev/pts/ptmx", F_OK) && umount("/dev/pts")) { |
896 | + SYSERROR("failed to umount 'dev/pts'"); |
897 | + return -1; |
898 | + } |
899 | + |
900 | + if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL, |
901 | + "newinstance,ptmxmode=0666")) { |
902 | + SYSERROR("failed to mount a new instance of '/dev/pts'"); |
903 | + return -1; |
904 | + } |
905 | + |
906 | + if (access("/dev/ptmx", F_OK)) { |
907 | + if (!symlink("/dev/pts/ptmx", "/dev/ptmx")) |
908 | + goto out; |
909 | + SYSERROR("failed to symlink '/dev/pts/ptmx'->'/dev/ptmx'"); |
910 | + return -1; |
911 | + } |
912 | + |
913 | + if (realpath("/dev/ptmx", target) && !strcmp(target, "/dev/pts/ptmx")) |
914 | + goto out; |
915 | + |
916 | + /* fallback here, /dev/pts/ptmx exists just mount bind */ |
917 | + if (mount("/dev/pts/ptmx", "/dev/ptmx", "none", MS_BIND, 0)) { |
918 | + SYSERROR("mount failed '/dev/pts/ptmx'->'/dev/ptmx'"); |
919 | + return -1; |
920 | + } |
921 | + |
922 | + INFO("created new pts instance"); |
923 | + |
924 | +out: |
925 | + return 0; |
926 | +} |
927 | + |
928 | +static int setup_personality(int persona) |
929 | +{ |
930 | + if (persona == -1) |
931 | + return 0; |
932 | + |
933 | + if (personality(persona) < 0) { |
934 | + SYSERROR("failed to set personality to '0x%x'", persona); |
935 | + return -1; |
936 | + } |
937 | + |
938 | + INFO("set personality to '0x%x'", persona); |
939 | + |
940 | + return 0; |
941 | +} |
942 | + |
943 | +static int setup_dev_console(const struct lxc_rootfs *rootfs, |
944 | + const struct lxc_console *console) |
945 | +{ |
946 | + char path[MAXPATHLEN]; |
947 | + struct stat s; |
948 | + int ret; |
949 | + |
950 | + ret = snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount); |
951 | + if (ret >= sizeof(path)) { |
952 | + ERROR("console path too long\n"); |
953 | + return -1; |
954 | + } |
955 | + |
956 | + if (access(path, F_OK)) { |
957 | + WARN("rootfs specified but no console found at '%s'", path); |
958 | + return 0; |
959 | + } |
960 | + |
961 | + if (console->peer == -1) { |
962 | + INFO("no console output required"); |
963 | + return 0; |
964 | + } |
965 | + |
966 | + if (stat(path, &s)) { |
967 | + SYSERROR("failed to stat '%s'", path); |
968 | + return -1; |
969 | + } |
970 | + |
971 | + if (chmod(console->name, s.st_mode)) { |
972 | + SYSERROR("failed to set mode '0%o' to '%s'", |
973 | + s.st_mode, console->name); |
974 | + return -1; |
975 | + } |
976 | + |
977 | + if (mount(console->name, path, "none", MS_BIND, 0)) { |
978 | + ERROR("failed to mount '%s' on '%s'", console->name, path); |
979 | + return -1; |
980 | + } |
981 | + |
982 | + INFO("console has been setup"); |
983 | + return 0; |
984 | +} |
985 | + |
986 | +static int setup_ttydir_console(const struct lxc_rootfs *rootfs, |
987 | + const struct lxc_console *console, |
988 | + char *ttydir) |
989 | +{ |
990 | + char path[MAXPATHLEN], lxcpath[MAXPATHLEN]; |
991 | + int ret; |
992 | + |
993 | + /* create rootfs/dev/<ttydir> directory */ |
994 | + ret = snprintf(path, sizeof(path), "%s/dev/%s", rootfs->mount, |
995 | + ttydir); |
996 | + if (ret >= sizeof(path)) |
997 | + return -1; |
998 | + ret = mkdir(path, 0755); |
999 | + if (ret && errno != EEXIST) { |
1000 | + SYSERROR("failed with errno %d to create %s\n", errno, path); |
1001 | + return -1; |
1002 | + } |
1003 | + INFO("created %s\n", path); |
1004 | + |
1005 | + ret = snprintf(lxcpath, sizeof(lxcpath), "%s/dev/%s/console", |
1006 | + rootfs->mount, ttydir); |
1007 | + if (ret >= sizeof(lxcpath)) { |
1008 | + ERROR("console path too long\n"); |
1009 | + return -1; |
1010 | + } |
1011 | + |
1012 | + snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount); |
1013 | + ret = unlink(path); |
1014 | + if (ret && errno != ENOENT) { |
1015 | + SYSERROR("error unlinking %s\n", path); |
1016 | + return -1; |
1017 | + } |
1018 | + |
1019 | + ret = creat(lxcpath, 0660); |
1020 | + if (ret==-1 && errno != EEXIST) { |
1021 | + SYSERROR("error %d creating %s\n", errno, lxcpath); |
1022 | + return -1; |
1023 | + } |
1024 | + close(ret); |
1025 | + |
1026 | + if (console->peer == -1) { |
1027 | + INFO("no console output required"); |
1028 | + return 0; |
1029 | + } |
1030 | + |
1031 | + if (mount(console->name, lxcpath, "none", MS_BIND, 0)) { |
1032 | + ERROR("failed to mount '%s' on '%s'", console->name, lxcpath); |
1033 | + return -1; |
1034 | + } |
1035 | + |
1036 | + /* create symlink from rootfs/dev/console to 'lxc/console' */ |
1037 | + ret = snprintf(lxcpath, sizeof(lxcpath), "%s/console", ttydir); |
1038 | + if (ret >= sizeof(lxcpath)) { |
1039 | + ERROR("lxc/console path too long"); |
1040 | + return -1; |
1041 | + } |
1042 | + ret = symlink(lxcpath, path); |
1043 | + if (ret) { |
1044 | + SYSERROR("failed to create symlink for console"); |
1045 | + return -1; |
1046 | + } |
1047 | + |
1048 | + INFO("console has been setup on %s", lxcpath); |
1049 | + |
1050 | + return 0; |
1051 | +} |
1052 | + |
1053 | +static int setup_console(const struct lxc_rootfs *rootfs, |
1054 | + const struct lxc_console *console, |
1055 | + char *ttydir) |
1056 | +{ |
1057 | + /* We don't have a rootfs, /dev/console will be shared */ |
1058 | + if (!rootfs->path) |
1059 | + return 0; |
1060 | + if (!ttydir) |
1061 | + return setup_dev_console(rootfs, console); |
1062 | + |
1063 | + return setup_ttydir_console(rootfs, console, ttydir); |
1064 | +} |
1065 | + |
1066 | +static int setup_kmsg(const struct lxc_rootfs *rootfs, |
1067 | + const struct lxc_console *console) |
1068 | +{ |
1069 | + char kpath[MAXPATHLEN]; |
1070 | + int ret; |
1071 | + |
1072 | + ret = snprintf(kpath, sizeof(kpath), "%s/dev/kmsg", rootfs->mount); |
1073 | + if (ret < 0 || ret >= sizeof(kpath)) |
1074 | + return -1; |
1075 | + |
1076 | + ret = unlink(kpath); |
1077 | + if (ret && errno != ENOENT) { |
1078 | + SYSERROR("error unlinking %s\n", kpath); |
1079 | + return -1; |
1080 | + } |
1081 | + |
1082 | + ret = symlink("console", kpath); |
1083 | + if (ret) { |
1084 | + SYSERROR("failed to create symlink for kmsg"); |
1085 | + return -1; |
1086 | + } |
1087 | + |
1088 | + return 0; |
1089 | +} |
1090 | + |
1091 | +static int setup_cgroup(const char *name, struct lxc_list *cgroups) |
1092 | +{ |
1093 | + struct lxc_list *iterator; |
1094 | + struct lxc_cgroup *cg; |
1095 | + int ret = -1; |
1096 | + |
1097 | + if (lxc_list_empty(cgroups)) |
1098 | + return 0; |
1099 | + |
1100 | + lxc_list_for_each(iterator, cgroups) { |
1101 | + |
1102 | + cg = iterator->elem; |
1103 | + |
1104 | + if (lxc_cgroup_set(name, cg->subsystem, cg->value)) |
1105 | + goto out; |
1106 | + |
1107 | + DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value); |
1108 | + } |
1109 | + |
1110 | + ret = 0; |
1111 | + INFO("cgroup has been setup"); |
1112 | +out: |
1113 | + return ret; |
1114 | +} |
1115 | + |
1116 | +static void parse_mntopt(char *opt, unsigned long *flags, char **data) |
1117 | +{ |
1118 | + struct mount_opt *mo; |
1119 | + |
1120 | + /* If opt is found in mount_opt, set or clear flags. |
1121 | + * Otherwise append it to data. */ |
1122 | + |
1123 | + for (mo = &mount_opt[0]; mo->name != NULL; mo++) { |
1124 | + if (!strncmp(opt, mo->name, strlen(mo->name))) { |
1125 | + if (mo->clear) |
1126 | + *flags &= ~mo->flag; |
1127 | + else |
1128 | + *flags |= mo->flag; |
1129 | + return; |
1130 | + } |
1131 | + } |
1132 | + |
1133 | + if (strlen(*data)) |
1134 | + strcat(*data, ","); |
1135 | + strcat(*data, opt); |
1136 | +} |
1137 | + |
1138 | +static int parse_mntopts(const char *mntopts, unsigned long *mntflags, |
1139 | + char **mntdata) |
1140 | +{ |
1141 | + char *s, *data; |
1142 | + char *p, *saveptr = NULL; |
1143 | + |
1144 | + *mntdata = NULL; |
1145 | + *mntflags = 0L; |
1146 | + |
1147 | + if (!mntopts) |
1148 | + return 0; |
1149 | + |
1150 | + s = strdup(mntopts); |
1151 | + if (!s) { |
1152 | + SYSERROR("failed to allocate memory"); |
1153 | + return -1; |
1154 | + } |
1155 | + |
1156 | + data = malloc(strlen(s) + 1); |
1157 | + if (!data) { |
1158 | + SYSERROR("failed to allocate memory"); |
1159 | + free(s); |
1160 | + return -1; |
1161 | + } |
1162 | + *data = 0; |
1163 | + |
1164 | + for (p = strtok_r(s, ",", &saveptr); p != NULL; |
1165 | + p = strtok_r(NULL, ",", &saveptr)) |
1166 | + parse_mntopt(p, mntflags, &data); |
1167 | + |
1168 | + if (*data) |
1169 | + *mntdata = data; |
1170 | + else |
1171 | + free(data); |
1172 | + free(s); |
1173 | + |
1174 | + return 0; |
1175 | +} |
1176 | + |
1177 | +static int mount_entry(const char *fsname, const char *target, |
1178 | + const char *fstype, unsigned long mountflags, |
1179 | + const char *data) |
1180 | +{ |
1181 | + if (mount(fsname, target, fstype, mountflags & ~MS_REMOUNT, data)) { |
1182 | + SYSERROR("failed to mount '%s' on '%s'", fsname, target); |
1183 | + return -1; |
1184 | + } |
1185 | + |
1186 | + if ((mountflags & MS_REMOUNT) || (mountflags & MS_BIND)) { |
1187 | + |
1188 | + DEBUG("remounting %s on %s to respect bind or remount options", |
1189 | + fsname, target); |
1190 | + |
1191 | + if (mount(fsname, target, fstype, |
1192 | + mountflags | MS_REMOUNT, data)) { |
1193 | + SYSERROR("failed to mount '%s' on '%s'", |
1194 | + fsname, target); |
1195 | + return -1; |
1196 | + } |
1197 | + } |
1198 | + |
1199 | + DEBUG("mounted '%s' on '%s', type '%s'", fsname, target, fstype); |
1200 | + |
1201 | + return 0; |
1202 | +} |
1203 | + |
1204 | +static inline int mount_entry_on_systemfs(struct mntent *mntent) |
1205 | +{ |
1206 | + unsigned long mntflags; |
1207 | + char *mntdata; |
1208 | + int ret; |
1209 | + |
1210 | + if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) { |
1211 | + ERROR("failed to parse mount option '%s'", mntent->mnt_opts); |
1212 | + return -1; |
1213 | + } |
1214 | + |
1215 | + ret = mount_entry(mntent->mnt_fsname, mntent->mnt_dir, |
1216 | + mntent->mnt_type, mntflags, mntdata); |
1217 | + |
1218 | + free(mntdata); |
1219 | + |
1220 | + return ret; |
1221 | +} |
1222 | + |
1223 | +static int mount_entry_on_absolute_rootfs(struct mntent *mntent, |
1224 | + const struct lxc_rootfs *rootfs, |
1225 | + const char *lxc_name) |
1226 | +{ |
1227 | + char *aux; |
1228 | + char path[MAXPATHLEN]; |
1229 | + unsigned long mntflags; |
1230 | + char *mntdata; |
1231 | + int r, ret = 0, offset; |
1232 | + |
1233 | + if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) { |
1234 | + ERROR("failed to parse mount option '%s'", mntent->mnt_opts); |
1235 | + return -1; |
1236 | + } |
1237 | + |
1238 | + /* if rootfs->path is a blockdev path, allow container fstab to |
1239 | + * use /var/lib/lxc/CN/rootfs as the target prefix */ |
1240 | + r = snprintf(path, MAXPATHLEN, "/var/lib/lxc/%s/rootfs", lxc_name); |
1241 | + if (r < 0 || r >= MAXPATHLEN) |
1242 | + goto skipvarlib; |
1243 | + |
1244 | + aux = strstr(mntent->mnt_dir, path); |
1245 | + if (aux) { |
1246 | + offset = strlen(path); |
1247 | + goto skipabs; |
1248 | + } |
1249 | + |
1250 | +skipvarlib: |
1251 | + aux = strstr(mntent->mnt_dir, rootfs->path); |
1252 | + if (!aux) { |
1253 | + WARN("ignoring mount point '%s'", mntent->mnt_dir); |
1254 | + goto out; |
1255 | + } |
1256 | + offset = strlen(rootfs->path); |
1257 | + |
1258 | +skipabs: |
1259 | + |
1260 | + r = snprintf(path, MAXPATHLEN, "%s/%s", rootfs->mount, |
1261 | + aux + offset); |
1262 | + if (r < 0 || r >= MAXPATHLEN) { |
1263 | + WARN("pathnme too long for '%s'", mntent->mnt_dir); |
1264 | + ret = -1; |
1265 | + goto out; |
1266 | + } |
1267 | + |
1268 | + |
1269 | + ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, |
1270 | + mntflags, mntdata); |
1271 | + |
1272 | +out: |
1273 | + free(mntdata); |
1274 | + return ret; |
1275 | +} |
1276 | + |
1277 | +static int mount_entry_on_relative_rootfs(struct mntent *mntent, |
1278 | + const char *rootfs) |
1279 | +{ |
1280 | + char path[MAXPATHLEN]; |
1281 | + unsigned long mntflags; |
1282 | + char *mntdata; |
1283 | + int ret; |
1284 | + |
1285 | + if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) { |
1286 | + ERROR("failed to parse mount option '%s'", mntent->mnt_opts); |
1287 | + return -1; |
1288 | + } |
1289 | + |
1290 | + /* relative to root mount point */ |
1291 | + ret = snprintf(path, sizeof(path), "%s/%s", rootfs, mntent->mnt_dir); |
1292 | + if (ret >= sizeof(path)) { |
1293 | + ERROR("path name too long"); |
1294 | + return -1; |
1295 | + } |
1296 | + |
1297 | + ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type, |
1298 | + mntflags, mntdata); |
1299 | + |
1300 | + free(mntdata); |
1301 | + |
1302 | + return ret; |
1303 | +} |
1304 | + |
1305 | +static int mount_file_entries(const struct lxc_rootfs *rootfs, FILE *file, |
1306 | + const char *lxc_name) |
1307 | +{ |
1308 | + struct mntent *mntent; |
1309 | + int ret = -1; |
1310 | + |
1311 | + while ((mntent = getmntent(file))) { |
1312 | + |
1313 | + if (!rootfs->path) { |
1314 | + if (mount_entry_on_systemfs(mntent)) |
1315 | + goto out; |
1316 | + continue; |
1317 | + } |
1318 | + |
1319 | + /* We have a separate root, mounts are relative to it */ |
1320 | + if (mntent->mnt_dir[0] != '/') { |
1321 | + if (mount_entry_on_relative_rootfs(mntent, |
1322 | + rootfs->mount)) |
1323 | + goto out; |
1324 | + continue; |
1325 | + } |
1326 | + |
1327 | + if (mount_entry_on_absolute_rootfs(mntent, rootfs, lxc_name)) |
1328 | + goto out; |
1329 | + } |
1330 | + |
1331 | + ret = 0; |
1332 | + |
1333 | + INFO("mount points have been setup"); |
1334 | +out: |
1335 | + return ret; |
1336 | +} |
1337 | + |
1338 | +static int setup_mount(const struct lxc_rootfs *rootfs, const char *fstab, |
1339 | + const char *lxc_name) |
1340 | +{ |
1341 | + FILE *file; |
1342 | + int ret; |
1343 | + |
1344 | + if (!fstab) |
1345 | + return 0; |
1346 | + |
1347 | + file = setmntent(fstab, "r"); |
1348 | + if (!file) { |
1349 | + SYSERROR("failed to use '%s'", fstab); |
1350 | + return -1; |
1351 | + } |
1352 | + |
1353 | + ret = mount_file_entries(rootfs, file, lxc_name); |
1354 | + |
1355 | + endmntent(file); |
1356 | + return ret; |
1357 | +} |
1358 | + |
1359 | +static int setup_mount_entries(const struct lxc_rootfs *rootfs, struct lxc_list *mount, |
1360 | + const char *lxc_name) |
1361 | +{ |
1362 | + FILE *file; |
1363 | + struct lxc_list *iterator; |
1364 | + char *mount_entry; |
1365 | + int ret; |
1366 | + |
1367 | + file = tmpfile(); |
1368 | + if (!file) { |
1369 | + ERROR("tmpfile error: %m"); |
1370 | + return -1; |
1371 | + } |
1372 | + |
1373 | + lxc_list_for_each(iterator, mount) { |
1374 | + mount_entry = iterator->elem; |
1375 | + fprintf(file, "%s\n", mount_entry); |
1376 | + } |
1377 | + |
1378 | + rewind(file); |
1379 | + |
1380 | + ret = mount_file_entries(rootfs, file, lxc_name); |
1381 | + |
1382 | + fclose(file); |
1383 | + return ret; |
1384 | +} |
1385 | + |
1386 | +static int setup_caps(struct lxc_list *caps) |
1387 | +{ |
1388 | + struct lxc_list *iterator; |
1389 | + char *drop_entry; |
1390 | + char *ptr; |
1391 | + int i, capid; |
1392 | + |
1393 | + lxc_list_for_each(iterator, caps) { |
1394 | + |
1395 | + drop_entry = iterator->elem; |
1396 | + |
1397 | + capid = -1; |
1398 | + |
1399 | + for (i = 0; i < sizeof(caps_opt)/sizeof(caps_opt[0]); i++) { |
1400 | + |
1401 | + if (strcmp(drop_entry, caps_opt[i].name)) |
1402 | + continue; |
1403 | + |
1404 | + capid = caps_opt[i].value; |
1405 | + break; |
1406 | + } |
1407 | + |
1408 | + if (capid < 0) { |
1409 | + /* try to see if it's numeric, so the user may specify |
1410 | + * capabilities that the running kernel knows about but |
1411 | + * we don't */ |
1412 | + capid = strtol(drop_entry, &ptr, 10); |
1413 | + if (!ptr || *ptr != '\0' || |
1414 | + capid == LONG_MIN || capid == LONG_MAX) |
1415 | + /* not a valid number */ |
1416 | + capid = -1; |
1417 | + else if (capid > lxc_caps_last_cap()) |
1418 | + /* we have a number but it's not a valid |
1419 | + * capability */ |
1420 | + capid = -1; |
1421 | + } |
1422 | + |
1423 | + if (capid < 0) { |
1424 | + ERROR("unknown capability %s", drop_entry); |
1425 | + return -1; |
1426 | + } |
1427 | + |
1428 | + DEBUG("drop capability '%s' (%d)", drop_entry, capid); |
1429 | + |
1430 | + if (prctl(PR_CAPBSET_DROP, capid, 0, 0, 0)) { |
1431 | + SYSERROR("failed to remove %s capability", drop_entry); |
1432 | + return -1; |
1433 | + } |
1434 | + |
1435 | + } |
1436 | + |
1437 | + DEBUG("capabilities has been setup"); |
1438 | + |
1439 | + return 0; |
1440 | +} |
1441 | + |
1442 | +static int setup_hw_addr(char *hwaddr, const char *ifname) |
1443 | +{ |
1444 | + struct sockaddr sockaddr; |
1445 | + struct ifreq ifr; |
1446 | + int ret, fd; |
1447 | + |
1448 | + ret = lxc_convert_mac(hwaddr, &sockaddr); |
1449 | + if (ret) { |
1450 | + ERROR("mac address '%s' conversion failed : %s", |
1451 | + hwaddr, strerror(-ret)); |
1452 | + return -1; |
1453 | + } |
1454 | + |
1455 | + memcpy(ifr.ifr_name, ifname, IFNAMSIZ); |
1456 | + memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr)); |
1457 | + |
1458 | + fd = socket(AF_INET, SOCK_DGRAM, 0); |
1459 | + if (fd < 0) { |
1460 | + ERROR("socket failure : %s", strerror(errno)); |
1461 | + return -1; |
1462 | + } |
1463 | + |
1464 | + ret = ioctl(fd, SIOCSIFHWADDR, &ifr); |
1465 | + close(fd); |
1466 | + if (ret) |
1467 | + ERROR("ioctl failure : %s", strerror(errno)); |
1468 | + |
1469 | + DEBUG("mac address '%s' on '%s' has been setup", hwaddr, ifname); |
1470 | + |
1471 | + return ret; |
1472 | +} |
1473 | + |
1474 | +static int setup_ipv4_addr(struct lxc_list *ip, int ifindex) |
1475 | +{ |
1476 | + struct lxc_list *iterator; |
1477 | + struct lxc_inetdev *inetdev; |
1478 | + int err; |
1479 | + |
1480 | + lxc_list_for_each(iterator, ip) { |
1481 | + |
1482 | + inetdev = iterator->elem; |
1483 | + |
1484 | + err = lxc_ipv4_addr_add(ifindex, &inetdev->addr, |
1485 | + &inetdev->bcast, inetdev->prefix); |
1486 | + if (err) { |
1487 | + ERROR("failed to setup_ipv4_addr ifindex %d : %s", |
1488 | + ifindex, strerror(-err)); |
1489 | + return -1; |
1490 | + } |
1491 | + } |
1492 | + |
1493 | + return 0; |
1494 | +} |
1495 | + |
1496 | +static int setup_ipv6_addr(struct lxc_list *ip, int ifindex) |
1497 | +{ |
1498 | + struct lxc_list *iterator; |
1499 | + struct lxc_inet6dev *inet6dev; |
1500 | + int err; |
1501 | + |
1502 | + lxc_list_for_each(iterator, ip) { |
1503 | + |
1504 | + inet6dev = iterator->elem; |
1505 | + |
1506 | + err = lxc_ipv6_addr_add(ifindex, &inet6dev->addr, |
1507 | + &inet6dev->mcast, &inet6dev->acast, |
1508 | + inet6dev->prefix); |
1509 | + if (err) { |
1510 | + ERROR("failed to setup_ipv6_addr ifindex %d : %s", |
1511 | + ifindex, strerror(-err)); |
1512 | + return -1; |
1513 | + } |
1514 | + } |
1515 | + |
1516 | + return 0; |
1517 | +} |
1518 | + |
1519 | +static int setup_netdev(struct lxc_netdev *netdev) |
1520 | +{ |
1521 | + char ifname[IFNAMSIZ]; |
1522 | + char *current_ifname = ifname; |
1523 | + int err; |
1524 | + |
1525 | + /* empty network namespace */ |
1526 | + if (!netdev->ifindex) { |
1527 | + if (netdev->flags & IFF_UP) { |
1528 | + err = lxc_netdev_up("lo"); |
1529 | + if (err) { |
1530 | + ERROR("failed to set the loopback up : %s", |
1531 | + strerror(-err)); |
1532 | + return -1; |
1533 | + } |
1534 | + } |
1535 | + return 0; |
1536 | + } |
1537 | + |
1538 | + /* retrieve the name of the interface */ |
1539 | + if (!if_indextoname(netdev->ifindex, current_ifname)) { |
1540 | + ERROR("no interface corresponding to index '%d'", |
1541 | + netdev->ifindex); |
1542 | + return -1; |
1543 | + } |
1544 | + |
1545 | + /* default: let the system to choose one interface name */ |
1546 | + if (!netdev->name) |
1547 | + netdev->name = netdev->type == LXC_NET_PHYS ? |
1548 | + netdev->link : "eth%d"; |
1549 | + |
1550 | + /* rename the interface name */ |
1551 | + err = lxc_netdev_rename_by_name(ifname, netdev->name); |
1552 | + if (err) { |
1553 | + ERROR("failed to rename %s->%s : %s", ifname, netdev->name, |
1554 | + strerror(-err)); |
1555 | + return -1; |
1556 | + } |
1557 | + |
1558 | + /* Re-read the name of the interface because its name has changed |
1559 | + * and would be automatically allocated by the system |
1560 | + */ |
1561 | + if (!if_indextoname(netdev->ifindex, current_ifname)) { |
1562 | + ERROR("no interface corresponding to index '%d'", |
1563 | + netdev->ifindex); |
1564 | + return -1; |
1565 | + } |
1566 | + |
1567 | + /* set a mac address */ |
1568 | + if (netdev->hwaddr) { |
1569 | + if (setup_hw_addr(netdev->hwaddr, current_ifname)) { |
1570 | + ERROR("failed to setup hw address for '%s'", |
1571 | + current_ifname); |
1572 | + return -1; |
1573 | + } |
1574 | + } |
1575 | + |
1576 | + /* setup ipv4 addresses on the interface */ |
1577 | + if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex)) { |
1578 | + ERROR("failed to setup ip addresses for '%s'", |
1579 | + ifname); |
1580 | + return -1; |
1581 | + } |
1582 | + |
1583 | + /* setup ipv6 addresses on the interface */ |
1584 | + if (setup_ipv6_addr(&netdev->ipv6, netdev->ifindex)) { |
1585 | + ERROR("failed to setup ipv6 addresses for '%s'", |
1586 | + ifname); |
1587 | + return -1; |
1588 | + } |
1589 | + |
1590 | + /* set the network device up */ |
1591 | + if (netdev->flags & IFF_UP) { |
1592 | + int err; |
1593 | + |
1594 | + err = lxc_netdev_up(current_ifname); |
1595 | + if (err) { |
1596 | + ERROR("failed to set '%s' up : %s", current_ifname, |
1597 | + strerror(-err)); |
1598 | + return -1; |
1599 | + } |
1600 | + |
1601 | + /* the network is up, make the loopback up too */ |
1602 | + err = lxc_netdev_up("lo"); |
1603 | + if (err) { |
1604 | + ERROR("failed to set the loopback up : %s", |
1605 | + strerror(-err)); |
1606 | + return -1; |
1607 | + } |
1608 | + } |
1609 | + |
1610 | + /* We can only set up the default routes after bringing |
1611 | + * up the interface, sine bringing up the interface adds |
1612 | + * the link-local routes and we can't add a default |
1613 | + * route if the gateway is not reachable. */ |
1614 | + |
1615 | + /* setup ipv4 gateway on the interface */ |
1616 | + if (netdev->ipv4_gateway) { |
1617 | + if (!(netdev->flags & IFF_UP)) { |
1618 | + ERROR("Cannot add ipv4 gateway for %s when not bringing up the interface", ifname); |
1619 | + return -1; |
1620 | + } |
1621 | + |
1622 | + if (lxc_list_empty(&netdev->ipv4)) { |
1623 | + ERROR("Cannot add ipv4 gateway for %s when not assigning an address", ifname); |
1624 | + return -1; |
1625 | + } |
1626 | + |
1627 | + err = lxc_ipv4_gateway_add(netdev->ifindex, netdev->ipv4_gateway); |
1628 | + if (err) { |
1629 | + ERROR("failed to setup ipv4 gateway for '%s': %s", |
1630 | + ifname, strerror(-err)); |
1631 | + if (netdev->ipv4_gateway_auto) { |
1632 | + char buf[INET_ADDRSTRLEN]; |
1633 | + inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf)); |
1634 | + ERROR("tried to set autodetected ipv4 gateway '%s'", buf); |
1635 | + } |
1636 | + return -1; |
1637 | + } |
1638 | + } |
1639 | + |
1640 | + /* setup ipv6 gateway on the interface */ |
1641 | + if (netdev->ipv6_gateway) { |
1642 | + if (!(netdev->flags & IFF_UP)) { |
1643 | + ERROR("Cannot add ipv6 gateway for %s when not bringing up the interface", ifname); |
1644 | + return -1; |
1645 | + } |
1646 | + |
1647 | + if (lxc_list_empty(&netdev->ipv6) && !IN6_IS_ADDR_LINKLOCAL(netdev->ipv6_gateway)) { |
1648 | + ERROR("Cannot add ipv6 gateway for %s when not assigning an address", ifname); |
1649 | + return -1; |
1650 | + } |
1651 | + |
1652 | + err = lxc_ipv6_gateway_add(netdev->ifindex, netdev->ipv6_gateway); |
1653 | + if (err) { |
1654 | + ERROR("failed to setup ipv6 gateway for '%s': %s", |
1655 | + ifname, strerror(-err)); |
1656 | + if (netdev->ipv6_gateway_auto) { |
1657 | + char buf[INET6_ADDRSTRLEN]; |
1658 | + inet_ntop(AF_INET6, netdev->ipv6_gateway, buf, sizeof(buf)); |
1659 | + ERROR("tried to set autodetected ipv6 gateway '%s'", buf); |
1660 | + } |
1661 | + return -1; |
1662 | + } |
1663 | + } |
1664 | + |
1665 | + DEBUG("'%s' has been setup", current_ifname); |
1666 | + |
1667 | + return 0; |
1668 | +} |
1669 | + |
1670 | +static int setup_network(struct lxc_list *network) |
1671 | +{ |
1672 | + struct lxc_list *iterator; |
1673 | + struct lxc_netdev *netdev; |
1674 | + |
1675 | + lxc_list_for_each(iterator, network) { |
1676 | + |
1677 | + netdev = iterator->elem; |
1678 | + |
1679 | + if (setup_netdev(netdev)) { |
1680 | + ERROR("failed to setup netdev"); |
1681 | + return -1; |
1682 | + } |
1683 | + } |
1684 | + |
1685 | + if (!lxc_list_empty(network)) |
1686 | + INFO("network has been setup"); |
1687 | + |
1688 | + return 0; |
1689 | +} |
1690 | + |
1691 | +static int setup_private_host_hw_addr(char *veth1) |
1692 | +{ |
1693 | + struct ifreq ifr; |
1694 | + int err; |
1695 | + int sockfd; |
1696 | + |
1697 | + sockfd = socket(AF_INET, SOCK_DGRAM, 0); |
1698 | + if (sockfd < 0) |
1699 | + return -errno; |
1700 | + |
1701 | + snprintf((char *)ifr.ifr_name, IFNAMSIZ, "%s", veth1); |
1702 | + err = ioctl(sockfd, SIOCGIFHWADDR, &ifr); |
1703 | + if (err < 0) { |
1704 | + close(sockfd); |
1705 | + return -errno; |
1706 | + } |
1707 | + |
1708 | + ifr.ifr_hwaddr.sa_data[0] = 0xfe; |
1709 | + err = ioctl(sockfd, SIOCSIFHWADDR, &ifr); |
1710 | + close(sockfd); |
1711 | + if (err < 0) |
1712 | + return -errno; |
1713 | + |
1714 | + DEBUG("mac address of host interface '%s' changed to private " |
1715 | + "%02x:%02x:%02x:%02x:%02x:%02x", veth1, |
1716 | + ifr.ifr_hwaddr.sa_data[0] & 0xff, |
1717 | + ifr.ifr_hwaddr.sa_data[1] & 0xff, |
1718 | + ifr.ifr_hwaddr.sa_data[2] & 0xff, |
1719 | + ifr.ifr_hwaddr.sa_data[3] & 0xff, |
1720 | + ifr.ifr_hwaddr.sa_data[4] & 0xff, |
1721 | + ifr.ifr_hwaddr.sa_data[5] & 0xff); |
1722 | + |
1723 | + return 0; |
1724 | +} |
1725 | + |
1726 | +struct lxc_conf *lxc_conf_init(void) |
1727 | +{ |
1728 | + struct lxc_conf *new; |
1729 | + int i; |
1730 | + |
1731 | + new = malloc(sizeof(*new)); |
1732 | + if (!new) { |
1733 | + ERROR("lxc_conf_init : %m"); |
1734 | + return NULL; |
1735 | + } |
1736 | + memset(new, 0, sizeof(*new)); |
1737 | + |
1738 | + new->umount_proc = 0; |
1739 | + new->personality = -1; |
1740 | + new->console.path = NULL; |
1741 | + new->console.peer = -1; |
1742 | + new->console.master = -1; |
1743 | + new->console.slave = -1; |
1744 | + new->console.name[0] = '\0'; |
1745 | + new->rootfs.mount = LXCROOTFSMOUNT; |
1746 | + lxc_list_init(&new->cgroup); |
1747 | + lxc_list_init(&new->network); |
1748 | + lxc_list_init(&new->mount_list); |
1749 | + lxc_list_init(&new->caps); |
1750 | + new->aa_profile = NULL; |
1751 | + for (i=0; i<NUM_LXC_HOOKS; i++) |
1752 | + lxc_list_init(&new->hooks[i]); |
1753 | + |
1754 | + return new; |
1755 | +} |
1756 | + |
1757 | +static int instanciate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev) |
1758 | +{ |
1759 | + char veth1buf[IFNAMSIZ], *veth1; |
1760 | + char veth2buf[IFNAMSIZ], *veth2; |
1761 | + int err; |
1762 | + |
1763 | + if (netdev->priv.veth_attr.pair) |
1764 | + veth1 = netdev->priv.veth_attr.pair; |
1765 | + else { |
1766 | + err = snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX"); |
1767 | + if (err >= sizeof(veth1buf)) { /* can't *really* happen, but... */ |
1768 | + ERROR("veth1 name too long"); |
1769 | + return -1; |
1770 | + } |
1771 | + veth1 = mktemp(veth1buf); |
1772 | + } |
1773 | + |
1774 | + snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX"); |
1775 | + veth2 = mktemp(veth2buf); |
1776 | + |
1777 | + if (!strlen(veth1) || !strlen(veth2)) { |
1778 | + ERROR("failed to allocate a temporary name"); |
1779 | + return -1; |
1780 | + } |
1781 | + |
1782 | + err = lxc_veth_create(veth1, veth2); |
1783 | + if (err) { |
1784 | + ERROR("failed to create %s-%s : %s", veth1, veth2, |
1785 | + strerror(-err)); |
1786 | + return -1; |
1787 | + } |
1788 | + |
1789 | + /* changing the high byte of the mac address to 0xfe, the bridge interface |
1790 | + * will always keep the host's mac address and not take the mac address |
1791 | + * of a container */ |
1792 | + err = setup_private_host_hw_addr(veth1); |
1793 | + if (err) { |
1794 | + ERROR("failed to change mac address of host interface '%s' : %s", |
1795 | + veth1, strerror(-err)); |
1796 | + goto out_delete; |
1797 | + } |
1798 | + |
1799 | + if (netdev->mtu) { |
1800 | + err = lxc_netdev_set_mtu(veth1, atoi(netdev->mtu)); |
1801 | + if (!err) |
1802 | + err = lxc_netdev_set_mtu(veth2, atoi(netdev->mtu)); |
1803 | + if (err) { |
1804 | + ERROR("failed to set mtu '%s' for %s-%s : %s", |
1805 | + netdev->mtu, veth1, veth2, strerror(-err)); |
1806 | + goto out_delete; |
1807 | + } |
1808 | + } |
1809 | + |
1810 | + if (netdev->link) { |
1811 | + err = lxc_bridge_attach(netdev->link, veth1); |
1812 | + if (err) { |
1813 | + ERROR("failed to attach '%s' to the bridge '%s' : %s", |
1814 | + veth1, netdev->link, strerror(-err)); |
1815 | + goto out_delete; |
1816 | + } |
1817 | + } |
1818 | + |
1819 | + netdev->ifindex = if_nametoindex(veth2); |
1820 | + if (!netdev->ifindex) { |
1821 | + ERROR("failed to retrieve the index for %s", veth2); |
1822 | + goto out_delete; |
1823 | + } |
1824 | + |
1825 | + err = lxc_netdev_up(veth1); |
1826 | + if (err) { |
1827 | + ERROR("failed to set %s up : %s", veth1, strerror(-err)); |
1828 | + goto out_delete; |
1829 | + } |
1830 | + |
1831 | + if (netdev->upscript) { |
1832 | + err = run_script(handler->name, "net", netdev->upscript, "up", |
1833 | + "veth", veth1, (char*) NULL); |
1834 | + if (err) |
1835 | + goto out_delete; |
1836 | + } |
1837 | + |
1838 | + DEBUG("instanciated veth '%s/%s', index is '%d'", |
1839 | + veth1, veth2, netdev->ifindex); |
1840 | + |
1841 | + return 0; |
1842 | + |
1843 | +out_delete: |
1844 | + lxc_netdev_delete_by_name(veth1); |
1845 | + return -1; |
1846 | +} |
1847 | + |
1848 | +static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev) |
1849 | +{ |
1850 | + char peerbuf[IFNAMSIZ], *peer; |
1851 | + int err; |
1852 | + |
1853 | + if (!netdev->link) { |
1854 | + ERROR("no link specified for macvlan netdev"); |
1855 | + return -1; |
1856 | + } |
1857 | + |
1858 | + err = snprintf(peerbuf, sizeof(peerbuf), "mcXXXXXX"); |
1859 | + if (err >= sizeof(peerbuf)) |
1860 | + return -1; |
1861 | + |
1862 | + peer = mktemp(peerbuf); |
1863 | + if (!strlen(peer)) { |
1864 | + ERROR("failed to make a temporary name"); |
1865 | + return -1; |
1866 | + } |
1867 | + |
1868 | + err = lxc_macvlan_create(netdev->link, peer, |
1869 | + netdev->priv.macvlan_attr.mode); |
1870 | + if (err) { |
1871 | + ERROR("failed to create macvlan interface '%s' on '%s' : %s", |
1872 | + peer, netdev->link, strerror(-err)); |
1873 | + return -1; |
1874 | + } |
1875 | + |
1876 | + netdev->ifindex = if_nametoindex(peer); |
1877 | + if (!netdev->ifindex) { |
1878 | + ERROR("failed to retrieve the index for %s", peer); |
1879 | + lxc_netdev_delete_by_name(peer); |
1880 | + return -1; |
1881 | + } |
1882 | + |
1883 | + if (netdev->upscript) { |
1884 | + err = run_script(handler->name, "net", netdev->upscript, "up", |
1885 | + "macvlan", netdev->link, (char*) NULL); |
1886 | + if (err) |
1887 | + return -1; |
1888 | + } |
1889 | + |
1890 | + DEBUG("instanciated macvlan '%s', index is '%d' and mode '%d'", |
1891 | + peer, netdev->ifindex, netdev->priv.macvlan_attr.mode); |
1892 | + |
1893 | + return 0; |
1894 | +} |
1895 | + |
1896 | +/* XXX: merge with instanciate_macvlan */ |
1897 | +static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev) |
1898 | +{ |
1899 | + char peer[IFNAMSIZ]; |
1900 | + int err; |
1901 | + |
1902 | + if (!netdev->link) { |
1903 | + ERROR("no link specified for vlan netdev"); |
1904 | + return -1; |
1905 | + } |
1906 | + |
1907 | + err = snprintf(peer, sizeof(peer), "vlan%d", netdev->priv.vlan_attr.vid); |
1908 | + if (err >= sizeof(peer)) { |
1909 | + ERROR("peer name too long"); |
1910 | + return -1; |
1911 | + } |
1912 | + |
1913 | + err = lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid); |
1914 | + if (err) { |
1915 | + ERROR("failed to create vlan interface '%s' on '%s' : %s", |
1916 | + peer, netdev->link, strerror(-err)); |
1917 | + return -1; |
1918 | + } |
1919 | + |
1920 | + netdev->ifindex = if_nametoindex(peer); |
1921 | + if (!netdev->ifindex) { |
1922 | + ERROR("failed to retrieve the ifindex for %s", peer); |
1923 | + lxc_netdev_delete_by_name(peer); |
1924 | + return -1; |
1925 | + } |
1926 | + |
1927 | + DEBUG("instanciated vlan '%s', ifindex is '%d'", " vlan1000", |
1928 | + netdev->ifindex); |
1929 | + |
1930 | + return 0; |
1931 | +} |
1932 | + |
1933 | +static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev) |
1934 | +{ |
1935 | + if (!netdev->link) { |
1936 | + ERROR("no link specified for the physical interface"); |
1937 | + return -1; |
1938 | + } |
1939 | + |
1940 | + netdev->ifindex = if_nametoindex(netdev->link); |
1941 | + if (!netdev->ifindex) { |
1942 | + ERROR("failed to retrieve the index for %s", netdev->link); |
1943 | + return -1; |
1944 | + } |
1945 | + |
1946 | + if (netdev->upscript) { |
1947 | + int err; |
1948 | + err = run_script(handler->name, "net", netdev->upscript, |
1949 | + "up", "phys", netdev->link, (char*) NULL); |
1950 | + if (err) |
1951 | + return -1; |
1952 | + } |
1953 | + |
1954 | + return 0; |
1955 | +} |
1956 | + |
1957 | +static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev) |
1958 | +{ |
1959 | + netdev->ifindex = 0; |
1960 | + if (netdev->upscript) { |
1961 | + int err; |
1962 | + err = run_script(handler->name, "net", netdev->upscript, |
1963 | + "up", "empty", (char*) NULL); |
1964 | + if (err) |
1965 | + return -1; |
1966 | + } |
1967 | + return 0; |
1968 | +} |
1969 | + |
1970 | +int lxc_create_network(struct lxc_handler *handler) |
1971 | +{ |
1972 | + struct lxc_list *network = &handler->conf->network; |
1973 | + struct lxc_list *iterator; |
1974 | + struct lxc_netdev *netdev; |
1975 | + |
1976 | + lxc_list_for_each(iterator, network) { |
1977 | + |
1978 | + netdev = iterator->elem; |
1979 | + |
1980 | + if (netdev->type < 0 || netdev->type > LXC_NET_MAXCONFTYPE) { |
1981 | + ERROR("invalid network configuration type '%d'", |
1982 | + netdev->type); |
1983 | + return -1; |
1984 | + } |
1985 | + |
1986 | + if (netdev_conf[netdev->type](handler, netdev)) { |
1987 | + ERROR("failed to create netdev"); |
1988 | + return -1; |
1989 | + } |
1990 | + |
1991 | + } |
1992 | + |
1993 | + return 0; |
1994 | +} |
1995 | + |
1996 | +void lxc_delete_network(struct lxc_list *network) |
1997 | +{ |
1998 | + struct lxc_list *iterator; |
1999 | + struct lxc_netdev *netdev; |
2000 | + |
2001 | + lxc_list_for_each(iterator, network) { |
2002 | + netdev = iterator->elem; |
2003 | + if (netdev->ifindex == 0) |
2004 | + continue; |
2005 | + |
2006 | + if (netdev->type == LXC_NET_PHYS) { |
2007 | + if (lxc_netdev_rename_by_index(netdev->ifindex, netdev->link)) |
2008 | + WARN("failed to rename to the initial name the " \ |
2009 | + "netdev '%s'", netdev->link); |
2010 | + continue; |
2011 | + } |
2012 | + |
2013 | + /* Recent kernel remove the virtual interfaces when the network |
2014 | + * namespace is destroyed but in case we did not moved the |
2015 | + * interface to the network namespace, we have to destroy it |
2016 | + */ |
2017 | + if (lxc_netdev_delete_by_index(netdev->ifindex)) |
2018 | + WARN("failed to remove interface '%s'", netdev->name); |
2019 | + } |
2020 | +} |
2021 | + |
2022 | +int lxc_assign_network(struct lxc_list *network, pid_t pid) |
2023 | +{ |
2024 | + struct lxc_list *iterator; |
2025 | + struct lxc_netdev *netdev; |
2026 | + int err; |
2027 | + |
2028 | + lxc_list_for_each(iterator, network) { |
2029 | + |
2030 | + netdev = iterator->elem; |
2031 | + |
2032 | + /* empty network namespace, nothing to move */ |
2033 | + if (!netdev->ifindex) |
2034 | + continue; |
2035 | + |
2036 | + err = lxc_netdev_move_by_index(netdev->ifindex, pid); |
2037 | + if (err) { |
2038 | + ERROR("failed to move '%s' to the container : %s", |
2039 | + netdev->link, strerror(-err)); |
2040 | + return -1; |
2041 | + } |
2042 | + |
2043 | + DEBUG("move '%s' to '%d'", netdev->name, pid); |
2044 | + } |
2045 | + |
2046 | + return 0; |
2047 | +} |
2048 | + |
2049 | +int lxc_find_gateway_addresses(struct lxc_handler *handler) |
2050 | +{ |
2051 | + struct lxc_list *network = &handler->conf->network; |
2052 | + struct lxc_list *iterator; |
2053 | + struct lxc_netdev *netdev; |
2054 | + int link_index; |
2055 | + |
2056 | + lxc_list_for_each(iterator, network) { |
2057 | + netdev = iterator->elem; |
2058 | + |
2059 | + if (!netdev->ipv4_gateway_auto && !netdev->ipv6_gateway_auto) |
2060 | + continue; |
2061 | + |
2062 | + if (netdev->type != LXC_NET_VETH && netdev->type != LXC_NET_MACVLAN) { |
2063 | + ERROR("gateway = auto only supported for " |
2064 | + "veth and macvlan"); |
2065 | + return -1; |
2066 | + } |
2067 | + |
2068 | + if (!netdev->link) { |
2069 | + ERROR("gateway = auto needs a link interface"); |
2070 | + return -1; |
2071 | + } |
2072 | + |
2073 | + link_index = if_nametoindex(netdev->link); |
2074 | + if (!link_index) |
2075 | + return -EINVAL; |
2076 | + |
2077 | + if (netdev->ipv4_gateway_auto) { |
2078 | + if (lxc_ipv4_addr_get(link_index, &netdev->ipv4_gateway)) { |
2079 | + ERROR("failed to automatically find ipv4 gateway " |
2080 | + "address from link interface '%s'", netdev->link); |
2081 | + return -1; |
2082 | + } |
2083 | + } |
2084 | + |
2085 | + if (netdev->ipv6_gateway_auto) { |
2086 | + if (lxc_ipv6_addr_get(link_index, &netdev->ipv6_gateway)) { |
2087 | + ERROR("failed to automatically find ipv6 gateway " |
2088 | + "address from link interface '%s'", netdev->link); |
2089 | + return -1; |
2090 | + } |
2091 | + } |
2092 | + } |
2093 | + |
2094 | + return 0; |
2095 | +} |
2096 | + |
2097 | +int lxc_create_tty(const char *name, struct lxc_conf *conf) |
2098 | +{ |
2099 | + struct lxc_tty_info *tty_info = &conf->tty_info; |
2100 | + int i; |
2101 | + |
2102 | + /* no tty in the configuration */ |
2103 | + if (!conf->tty) |
2104 | + return 0; |
2105 | + |
2106 | + tty_info->pty_info = |
2107 | + malloc(sizeof(*tty_info->pty_info)*conf->tty); |
2108 | + if (!tty_info->pty_info) { |
2109 | + SYSERROR("failed to allocate pty_info"); |
2110 | + return -1; |
2111 | + } |
2112 | + |
2113 | + for (i = 0; i < conf->tty; i++) { |
2114 | + |
2115 | + struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; |
2116 | + |
2117 | + if (openpty(&pty_info->master, &pty_info->slave, |
2118 | + pty_info->name, NULL, NULL)) { |
2119 | + SYSERROR("failed to create pty #%d", i); |
2120 | + tty_info->nbtty = i; |
2121 | + lxc_delete_tty(tty_info); |
2122 | + return -1; |
2123 | + } |
2124 | + |
2125 | + DEBUG("allocated pty '%s' (%d/%d)", |
2126 | + pty_info->name, pty_info->master, pty_info->slave); |
2127 | + |
2128 | + /* Prevent leaking the file descriptors to the container */ |
2129 | + fcntl(pty_info->master, F_SETFD, FD_CLOEXEC); |
2130 | + fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC); |
2131 | + |
2132 | + pty_info->busy = 0; |
2133 | + } |
2134 | + |
2135 | + tty_info->nbtty = conf->tty; |
2136 | + |
2137 | + INFO("tty's configured"); |
2138 | + |
2139 | + return 0; |
2140 | +} |
2141 | + |
2142 | +void lxc_delete_tty(struct lxc_tty_info *tty_info) |
2143 | +{ |
2144 | + int i; |
2145 | + |
2146 | + for (i = 0; i < tty_info->nbtty; i++) { |
2147 | + struct lxc_pty_info *pty_info = &tty_info->pty_info[i]; |
2148 | + |
2149 | + close(pty_info->master); |
2150 | + close(pty_info->slave); |
2151 | + } |
2152 | + |
2153 | + free(tty_info->pty_info); |
2154 | + tty_info->nbtty = 0; |
2155 | +} |
2156 | + |
2157 | +/* |
2158 | + * make sure /proc/self exists, and points to '1', since we are the |
2159 | + * container init. |
2160 | + * Else mount /proc. Return 0 if proc was |
2161 | + * already mounted, 1 if we mounted it, -1 if we failed. |
2162 | + */ |
2163 | +static int mount_proc_if_needed(char *root_src, char *rootfs_tgt) |
2164 | +{ |
2165 | + char path[MAXPATHLEN]; |
2166 | + char link[20]; |
2167 | + int linklen, ret; |
2168 | + |
2169 | + ret = snprintf(path, MAXPATHLEN, "%s/proc/self", root_src ? rootfs_tgt : ""); |
2170 | + if (ret < 0 || ret >= MAXPATHLEN) { |
2171 | + SYSERROR("proc path name too long"); |
2172 | + return -1; |
2173 | + } |
2174 | + memset(link, 0, 20); |
2175 | + linklen = readlink(path, link, 20); |
2176 | + INFO("I am %d, /proc/self points to %s\n", getpid(), link); |
2177 | + ret = snprintf(path, MAXPATHLEN, "%s/proc", root_src ? rootfs_tgt : ""); |
2178 | + if (linklen < 0) /* /proc not mounted */ |
2179 | + goto domount; |
2180 | + /* can't be longer than rootfs/proc/1 */ |
2181 | + if (strncmp(link, "1", linklen) != 0) { |
2182 | + /* wrong /procs mounted */ |
2183 | + umount2(path, MNT_DETACH); /* ignore failure */ |
2184 | + goto domount; |
2185 | + } |
2186 | + /* the right proc is already mounted */ |
2187 | + return 0; |
2188 | + |
2189 | +domount: |
2190 | + if (mount("proc", path, "proc", 0, NULL)) |
2191 | + return -1; |
2192 | + INFO("Mounted /proc for the container\n"); |
2193 | + return 1; |
2194 | +} |
2195 | + |
2196 | +int lxc_setup(const char *name, struct lxc_conf *lxc_conf) |
2197 | +{ |
2198 | + int mounted; |
2199 | + |
2200 | + if (setup_utsname(lxc_conf->utsname)) { |
2201 | + ERROR("failed to setup the utsname for '%s'", name); |
2202 | + return -1; |
2203 | + } |
2204 | + |
2205 | + if (setup_network(&lxc_conf->network)) { |
2206 | + ERROR("failed to setup the network for '%s'", name); |
2207 | + return -1; |
2208 | + } |
2209 | + |
2210 | + if (run_lxc_hooks(name, "pre-mount", lxc_conf)) { |
2211 | + ERROR("failed to run pre-mount hooks for container '%s'.", name); |
2212 | + return -1; |
2213 | + } |
2214 | + |
2215 | + if (setup_rootfs(&lxc_conf->rootfs)) { |
2216 | + ERROR("failed to setup rootfs for '%s'", name); |
2217 | + return -1; |
2218 | + } |
2219 | + |
2220 | + if (setup_mount(&lxc_conf->rootfs, lxc_conf->fstab, name)) { |
2221 | + ERROR("failed to setup the mounts for '%s'", name); |
2222 | + return -1; |
2223 | + } |
2224 | + |
2225 | + if (setup_mount_entries(&lxc_conf->rootfs, &lxc_conf->mount_list, name)) { |
2226 | + ERROR("failed to setup the mount entries for '%s'", name); |
2227 | + return -1; |
2228 | + } |
2229 | + |
2230 | + if (setup_cgroup(name, &lxc_conf->cgroup)) { |
2231 | + ERROR("failed to setup the cgroups for '%s'", name); |
2232 | + return -1; |
2233 | + } |
2234 | + if (run_lxc_hooks(name, "mount", lxc_conf)) { |
2235 | + ERROR("failed to run mount hooks for container '%s'.", name); |
2236 | + return -1; |
2237 | + } |
2238 | + |
2239 | + if (setup_console(&lxc_conf->rootfs, &lxc_conf->console, lxc_conf->ttydir)) { |
2240 | + ERROR("failed to setup the console for '%s'", name); |
2241 | + return -1; |
2242 | + } |
2243 | + |
2244 | + if (setup_kmsg(&lxc_conf->rootfs, &lxc_conf->console)) { |
2245 | + ERROR("failed to setup kmsg for '%s'", name); |
2246 | + return -1; |
2247 | + } |
2248 | + |
2249 | + if (setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info, lxc_conf->ttydir)) { |
2250 | + ERROR("failed to setup the ttys for '%s'", name); |
2251 | + return -1; |
2252 | + } |
2253 | + |
2254 | + /* aa_change_onexec makes more sense since we want to transition when |
2255 | + * /sbin/init is exec'd. But the transitions doesn't seem to work |
2256 | + * then (refused). aa_change_onexec will work since we're doing it |
2257 | + * right before the exec, so we'll just use that for now. |
2258 | + * In case the container fstab didn't mount /proc, we mount it. |
2259 | + */ |
2260 | + INFO("rootfs path is .%s., mount is .%s.", lxc_conf->rootfs.path, |
2261 | + lxc_conf->rootfs.mount); |
2262 | + |
2263 | + mounted = mount_proc_if_needed(lxc_conf->rootfs.path, lxc_conf->rootfs.mount); |
2264 | + if (mounted == -1) { |
2265 | + SYSERROR("failed to mount /proc in the container."); |
2266 | + return -1; |
2267 | + } else if (mounted == 1) { |
2268 | + lxc_conf->umount_proc = 1; |
2269 | + } |
2270 | + |
2271 | + if (setup_pivot_root(&lxc_conf->rootfs)) { |
2272 | + ERROR("failed to set rootfs for '%s'", name); |
2273 | + return -1; |
2274 | + } |
2275 | + |
2276 | + if (setup_pts(lxc_conf->pts)) { |
2277 | + ERROR("failed to setup the new pts instance"); |
2278 | + return -1; |
2279 | + } |
2280 | + |
2281 | + if (setup_personality(lxc_conf->personality)) { |
2282 | + ERROR("failed to setup personality"); |
2283 | + return -1; |
2284 | + } |
2285 | + |
2286 | + if (setup_caps(&lxc_conf->caps)) { |
2287 | + ERROR("failed to drop capabilities"); |
2288 | + return -1; |
2289 | + } |
2290 | + |
2291 | + NOTICE("'%s' is setup.", name); |
2292 | + |
2293 | + return 0; |
2294 | +} |
2295 | + |
2296 | +int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf) |
2297 | +{ |
2298 | + int which = -1; |
2299 | + struct lxc_list *it; |
2300 | + |
2301 | + if (strcmp(hook, "pre-start") == 0) |
2302 | + which = LXCHOOK_PRESTART; |
2303 | + else if (strcmp(hook, "pre-mount") == 0) |
2304 | + which = LXCHOOK_PREMOUNT; |
2305 | + else if (strcmp(hook, "mount") == 0) |
2306 | + which = LXCHOOK_MOUNT; |
2307 | + else if (strcmp(hook, "start") == 0) |
2308 | + which = LXCHOOK_START; |
2309 | + else if (strcmp(hook, "post-stop") == 0) |
2310 | + which = LXCHOOK_POSTSTOP; |
2311 | + else |
2312 | + return -1; |
2313 | + lxc_list_for_each(it, &conf->hooks[which]) { |
2314 | + int ret; |
2315 | + char *hookname = it->elem; |
2316 | + ret = run_script(name, "lxc", hookname, hook, NULL); |
2317 | + if (ret) |
2318 | + return ret; |
2319 | + } |
2320 | + return 0; |
2321 | +} |
2322 | + |
2323 | +static void lxc_remove_nic(struct lxc_list *it) |
2324 | +{ |
2325 | + struct lxc_netdev *netdev = it->elem; |
2326 | + struct lxc_list *it2; |
2327 | + |
2328 | + lxc_list_del(it); |
2329 | + |
2330 | + if (netdev->link) |
2331 | + free(netdev->link); |
2332 | + if (netdev->name) |
2333 | + free(netdev->name); |
2334 | + if (netdev->upscript) |
2335 | + free(netdev->upscript); |
2336 | + if (netdev->hwaddr) |
2337 | + free(netdev->hwaddr); |
2338 | + if (netdev->mtu) |
2339 | + free(netdev->mtu); |
2340 | + if (netdev->ipv4_gateway) |
2341 | + free(netdev->ipv4_gateway); |
2342 | + if (netdev->ipv6_gateway) |
2343 | + free(netdev->ipv6_gateway); |
2344 | + lxc_list_for_each(it2, &netdev->ipv4) { |
2345 | + lxc_list_del(it2); |
2346 | + free(it2->elem); |
2347 | + free(it2); |
2348 | + } |
2349 | + lxc_list_for_each(it2, &netdev->ipv6) { |
2350 | + lxc_list_del(it2); |
2351 | + free(it2->elem); |
2352 | + free(it2); |
2353 | + } |
2354 | + free(it); |
2355 | +} |
2356 | + |
2357 | +/* we get passed in something like '0', '0.ipv4' or '1.ipv6' */ |
2358 | +int lxc_clear_nic(struct lxc_conf *c, char *key) |
2359 | +{ |
2360 | + char *p1; |
2361 | + int ret, idx, i; |
2362 | + struct lxc_list *it; |
2363 | + struct lxc_netdev *netdev; |
2364 | + |
2365 | + p1 = index(key, '.'); |
2366 | + if (!p1 || *(p1+1) == '\0') |
2367 | + p1 = NULL; |
2368 | + |
2369 | + ret = sscanf(key, "%d", &idx); |
2370 | + if (ret != 1) return -1; |
2371 | + if (idx < 0) |
2372 | + return -1; |
2373 | + |
2374 | + i = 0; |
2375 | + lxc_list_for_each(it, &c->network) { |
2376 | + if (i == idx) |
2377 | + break; |
2378 | + i++; |
2379 | + } |
2380 | + if (i < idx) // we don't have that many nics defined |
2381 | + return -1; |
2382 | + |
2383 | + if (!it || !it->elem) |
2384 | + return -1; |
2385 | + |
2386 | + netdev = it->elem; |
2387 | + |
2388 | + if (!p1) { |
2389 | + lxc_remove_nic(it); |
2390 | + } else if (strcmp(p1, "ipv4") == 0) { |
2391 | + struct lxc_list *it2; |
2392 | + lxc_list_for_each(it2, &netdev->ipv4) { |
2393 | + lxc_list_del(it2); |
2394 | + free(it2->elem); |
2395 | + free(it2); |
2396 | + } |
2397 | + } else if (strcmp(p1, "ipv6") == 0) { |
2398 | + struct lxc_list *it2; |
2399 | + lxc_list_for_each(it2, &netdev->ipv6) { |
2400 | + lxc_list_del(it2); |
2401 | + free(it2->elem); |
2402 | + free(it2); |
2403 | + } |
2404 | + } else if (strcmp(p1, "link") == 0) { |
2405 | + if (netdev->link) { |
2406 | + free(netdev->link); |
2407 | + netdev->link = NULL; |
2408 | + } |
2409 | + } else if (strcmp(p1, "name") == 0) { |
2410 | + if (netdev->name) { |
2411 | + free(netdev->name); |
2412 | + netdev->name = NULL; |
2413 | + } |
2414 | + } else if (strcmp(p1, "script.up") == 0) { |
2415 | + if (netdev->upscript) { |
2416 | + free(netdev->upscript); |
2417 | + netdev->upscript = NULL; |
2418 | + } |
2419 | + } else if (strcmp(p1, "hwaddr") == 0) { |
2420 | + if (netdev->hwaddr) { |
2421 | + free(netdev->hwaddr); |
2422 | + netdev->hwaddr = NULL; |
2423 | + } |
2424 | + } else if (strcmp(p1, "mtu") == 0) { |
2425 | + if (netdev->mtu) { |
2426 | + free(netdev->mtu); |
2427 | + netdev->mtu = NULL; |
2428 | + } |
2429 | + } else if (strcmp(p1, "ipv4_gateway") == 0) { |
2430 | + if (netdev->ipv4_gateway) { |
2431 | + free(netdev->ipv4_gateway); |
2432 | + netdev->ipv4_gateway = NULL; |
2433 | + } |
2434 | + } else if (strcmp(p1, "ipv6_gateway") == 0) { |
2435 | + if (netdev->ipv6_gateway) { |
2436 | + free(netdev->ipv6_gateway); |
2437 | + netdev->ipv6_gateway = NULL; |
2438 | + } |
2439 | + } |
2440 | + else return -1; |
2441 | + |
2442 | + return 0; |
2443 | +} |
2444 | + |
2445 | +int lxc_clear_config_network(struct lxc_conf *c) |
2446 | +{ |
2447 | + struct lxc_list *it; |
2448 | + lxc_list_for_each(it, &c->network) { |
2449 | + lxc_remove_nic(it); |
2450 | + } |
2451 | + return 0; |
2452 | +} |
2453 | + |
2454 | +int lxc_clear_config_caps(struct lxc_conf *c) |
2455 | +{ |
2456 | + struct lxc_list *it; |
2457 | + |
2458 | + lxc_list_for_each(it, &c->caps) { |
2459 | + lxc_list_del(it); |
2460 | + free(it->elem); |
2461 | + free(it); |
2462 | + } |
2463 | + return 0; |
2464 | +} |
2465 | + |
2466 | +int lxc_clear_cgroups(struct lxc_conf *c, char *key) |
2467 | +{ |
2468 | + struct lxc_list *it; |
2469 | + bool all = false; |
2470 | + char *k = key + 11; |
2471 | + |
2472 | + if (strcmp(key, "lxc.cgroup") == 0) |
2473 | + all = true; |
2474 | + |
2475 | + lxc_list_for_each(it, &c->cgroup) { |
2476 | + struct lxc_cgroup *cg = it->elem; |
2477 | + if (!all && strcmp(cg->subsystem, k) != 0) |
2478 | + continue; |
2479 | + lxc_list_del(it); |
2480 | + free(cg->subsystem); |
2481 | + free(cg->value); |
2482 | + free(cg); |
2483 | + free(it); |
2484 | + } |
2485 | + return 0; |
2486 | +} |
2487 | + |
2488 | +int lxc_clear_mount_entries(struct lxc_conf *c) |
2489 | +{ |
2490 | + struct lxc_list *it; |
2491 | + |
2492 | + lxc_list_for_each(it, &c->mount_list) { |
2493 | + lxc_list_del(it); |
2494 | + free(it->elem); |
2495 | + free(it); |
2496 | + } |
2497 | + return 0; |
2498 | +} |
2499 | + |
2500 | +int lxc_clear_hooks(struct lxc_conf *c) |
2501 | +{ |
2502 | + struct lxc_list *it; |
2503 | + int i; |
2504 | + |
2505 | + for (i=0; i<NUM_LXC_HOOKS; i++) { |
2506 | + lxc_list_for_each(it, &c->hooks[i]) { |
2507 | + lxc_list_del(it); |
2508 | + free(it->elem); |
2509 | + free(it); |
2510 | + } |
2511 | + } |
2512 | + return 0; |
2513 | +} |
2514 | + |
2515 | +void lxc_conf_free(struct lxc_conf *conf) |
2516 | +{ |
2517 | + if (!conf) |
2518 | + return; |
2519 | + if (conf->console.path) |
2520 | + free(conf->console.path); |
2521 | + if (conf->rootfs.mount != LXCROOTFSMOUNT) |
2522 | + free(conf->rootfs.mount); |
2523 | + lxc_clear_config_network(conf); |
2524 | + if (conf->aa_profile) |
2525 | + free(conf->aa_profile); |
2526 | + lxc_clear_config_caps(conf); |
2527 | + lxc_clear_cgroups(conf, "lxc.cgroup"); |
2528 | + lxc_clear_hooks(conf); |
2529 | + lxc_clear_mount_entries(conf); |
2530 | + free(conf); |
2531 | +} |
2532 | |
2533 | === added file '.pc/0220-getitem-per-hook-type/src/lxc/conf.h' |
2534 | --- .pc/0220-getitem-per-hook-type/src/lxc/conf.h 1970-01-01 00:00:00 +0000 |
2535 | +++ .pc/0220-getitem-per-hook-type/src/lxc/conf.h 2012-09-14 20:24:18 +0000 |
2536 | @@ -0,0 +1,262 @@ |
2537 | +/* |
2538 | + * lxc: linux Container library |
2539 | + * |
2540 | + * (C) Copyright IBM Corp. 2007, 2008 |
2541 | + * |
2542 | + * Authors: |
2543 | + * Daniel Lezcano <dlezcano at fr.ibm.com> |
2544 | + * |
2545 | + * This library is free software; you can redistribute it and/or |
2546 | + * modify it under the terms of the GNU Lesser General Public |
2547 | + * License as published by the Free Software Foundation; either |
2548 | + * version 2.1 of the License, or (at your option) any later version. |
2549 | + * |
2550 | + * This library is distributed in the hope that it will be useful, |
2551 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2552 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2553 | + * Lesser General Public License for more details. |
2554 | + * |
2555 | + * You should have received a copy of the GNU Lesser General Public |
2556 | + * License along with this library; if not, write to the Free Software |
2557 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
2558 | + */ |
2559 | +#ifndef _conf_h |
2560 | +#define _conf_h |
2561 | + |
2562 | +#include <netinet/in.h> |
2563 | +#include <sys/param.h> |
2564 | +#include <stdbool.h> |
2565 | + |
2566 | +#include <lxc/list.h> |
2567 | + |
2568 | +#include <lxc/start.h> /* for lxc_handler */ |
2569 | + |
2570 | +enum { |
2571 | + LXC_NET_EMPTY, |
2572 | + LXC_NET_VETH, |
2573 | + LXC_NET_MACVLAN, |
2574 | + LXC_NET_PHYS, |
2575 | + LXC_NET_VLAN, |
2576 | + LXC_NET_MAXCONFTYPE, |
2577 | +}; |
2578 | + |
2579 | +/* |
2580 | + * Defines the structure to configure an ipv4 address |
2581 | + * @address : ipv4 address |
2582 | + * @broadcast : ipv4 broadcast address |
2583 | + * @mask : network mask |
2584 | + */ |
2585 | +struct lxc_inetdev { |
2586 | + struct in_addr addr; |
2587 | + struct in_addr bcast; |
2588 | + int prefix; |
2589 | +}; |
2590 | + |
2591 | +struct lxc_route { |
2592 | + struct in_addr addr; |
2593 | +}; |
2594 | + |
2595 | +/* |
2596 | + * Defines the structure to configure an ipv6 address |
2597 | + * @flags : set the address up |
2598 | + * @address : ipv6 address |
2599 | + * @broadcast : ipv6 broadcast address |
2600 | + * @mask : network mask |
2601 | + */ |
2602 | +struct lxc_inet6dev { |
2603 | + struct in6_addr addr; |
2604 | + struct in6_addr mcast; |
2605 | + struct in6_addr acast; |
2606 | + int prefix; |
2607 | +}; |
2608 | + |
2609 | +struct lxc_route6 { |
2610 | + struct in6_addr addr; |
2611 | +}; |
2612 | + |
2613 | +struct ifla_veth { |
2614 | + char *pair; /* pair name */ |
2615 | +}; |
2616 | + |
2617 | +struct ifla_vlan { |
2618 | + uint flags; |
2619 | + uint fmask; |
2620 | + ushort vid; |
2621 | + ushort pad; |
2622 | +}; |
2623 | + |
2624 | +struct ifla_macvlan { |
2625 | + int mode; /* private, vepa, bridge */ |
2626 | +}; |
2627 | + |
2628 | +union netdev_p { |
2629 | + struct ifla_veth veth_attr; |
2630 | + struct ifla_vlan vlan_attr; |
2631 | + struct ifla_macvlan macvlan_attr; |
2632 | +}; |
2633 | + |
2634 | +/* |
2635 | + * Defines a structure to configure a network device |
2636 | + * @link : lxc.network.link, name of bridge or host iface to attach if any |
2637 | + * @name : lxc.network.name, name of iface on the container side |
2638 | + * @flags : flag of the network device (IFF_UP, ... ) |
2639 | + * @ipv4 : a list of ipv4 addresses to be set on the network device |
2640 | + * @ipv6 : a list of ipv6 addresses to be set on the network device |
2641 | + * @upscript : a script filename to be executed during interface configuration |
2642 | + */ |
2643 | +struct lxc_netdev { |
2644 | + int type; |
2645 | + int flags; |
2646 | + int ifindex; |
2647 | + char *link; |
2648 | + char *name; |
2649 | + char *hwaddr; |
2650 | + char *mtu; |
2651 | + union netdev_p priv; |
2652 | + struct lxc_list ipv4; |
2653 | + struct lxc_list ipv6; |
2654 | + struct in_addr *ipv4_gateway; |
2655 | + bool ipv4_gateway_auto; |
2656 | + struct in6_addr *ipv6_gateway; |
2657 | + bool ipv6_gateway_auto; |
2658 | + char *upscript; |
2659 | +}; |
2660 | + |
2661 | +/* |
2662 | + * Defines a generic struct to configure the control group. |
2663 | + * It is up to the programmer to specify the right subsystem. |
2664 | + * @subsystem : the targetted subsystem |
2665 | + * @value : the value to set |
2666 | + */ |
2667 | +struct lxc_cgroup { |
2668 | + char *subsystem; |
2669 | + char *value; |
2670 | +}; |
2671 | + |
2672 | +/* |
2673 | + * Defines a structure containing a pty information for |
2674 | + * virtualizing a tty |
2675 | + * @name : the path name of the slave pty side |
2676 | + * @master : the file descriptor of the master |
2677 | + * @slave : the file descriptor of the slave |
2678 | + */ |
2679 | +struct lxc_pty_info { |
2680 | + char name[MAXPATHLEN]; |
2681 | + int master; |
2682 | + int slave; |
2683 | + int busy; |
2684 | +}; |
2685 | + |
2686 | +/* |
2687 | + * Defines the number of tty configured and contains the |
2688 | + * instanciated ptys |
2689 | + * @nbtty = number of configured ttys |
2690 | + */ |
2691 | +struct lxc_tty_info { |
2692 | + int nbtty; |
2693 | + struct lxc_pty_info *pty_info; |
2694 | +}; |
2695 | + |
2696 | +/* |
2697 | + * Defines the structure to store the console information |
2698 | + * @peer : the file descriptor put/get console traffic |
2699 | + * @name : the file name of the slave pty |
2700 | + */ |
2701 | +struct lxc_console { |
2702 | + int slave; |
2703 | + int master; |
2704 | + int peer; |
2705 | + char *path; |
2706 | + char name[MAXPATHLEN]; |
2707 | + struct termios *tios; |
2708 | +}; |
2709 | + |
2710 | +/* |
2711 | + * Defines a structure to store the rootfs location, the |
2712 | + * optionals pivot_root, rootfs mount paths |
2713 | + * @rootfs : a path to the rootfs |
2714 | + * @pivot_root : a path to a pivot_root location to be used |
2715 | + */ |
2716 | +struct lxc_rootfs { |
2717 | + char *path; |
2718 | + char *mount; |
2719 | + char *pivot; |
2720 | +}; |
2721 | + |
2722 | +/* |
2723 | + * Defines the global container configuration |
2724 | + * @rootfs : root directory to run the container |
2725 | + * @pivotdir : pivotdir path, if not set default will be used |
2726 | + * @mount : list of mount points |
2727 | + * @tty : numbers of tty |
2728 | + * @pts : new pts instance |
2729 | + * @mount_list : list of mount point (alternative to fstab file) |
2730 | + * @network : network configuration |
2731 | + * @utsname : container utsname |
2732 | + * @fstab : path to a fstab file format |
2733 | + * @caps : list of the capabilities |
2734 | + * @tty_info : tty data |
2735 | + * @console : console data |
2736 | + * @ttydir : directory (under /dev) in which to create console and ttys |
2737 | + * @aa_profile : apparmor profile to switch to |
2738 | + */ |
2739 | +enum lxchooks { |
2740 | + LXCHOOK_PRESTART, LXCHOOK_PREMOUNT, LXCHOOK_MOUNT, LXCHOOK_START, |
2741 | + LXCHOOK_POSTSTOP, NUM_LXC_HOOKS}; |
2742 | +extern char *lxchook_names[NUM_LXC_HOOKS]; |
2743 | + |
2744 | +struct lxc_conf { |
2745 | + char *fstab; |
2746 | + int tty; |
2747 | + int pts; |
2748 | + int reboot; |
2749 | + int need_utmp_watch; |
2750 | + int personality; |
2751 | + struct utsname *utsname; |
2752 | + struct lxc_list cgroup; |
2753 | + struct lxc_list network; |
2754 | + struct lxc_list mount_list; |
2755 | + struct lxc_list caps; |
2756 | + struct lxc_tty_info tty_info; |
2757 | + struct lxc_console console; |
2758 | + struct lxc_rootfs rootfs; |
2759 | + char *ttydir; |
2760 | + int close_all_fds; |
2761 | + char *aa_profile; |
2762 | + int umount_proc; |
2763 | + struct lxc_list hooks[NUM_LXC_HOOKS]; |
2764 | + char *seccomp; // filename with the seccomp rules |
2765 | + int maincmd_fd; |
2766 | +}; |
2767 | + |
2768 | +int run_lxc_hooks(const char *name, char *hook, struct lxc_conf *conf); |
2769 | + |
2770 | +/* |
2771 | + * Initialize the lxc configuration structure |
2772 | + */ |
2773 | +extern struct lxc_conf *lxc_conf_init(void); |
2774 | +extern void lxc_conf_free(struct lxc_conf *conf); |
2775 | + |
2776 | +extern int pin_rootfs(const char *rootfs); |
2777 | + |
2778 | +extern int lxc_create_network(struct lxc_handler *handler); |
2779 | +extern void lxc_delete_network(struct lxc_list *networks); |
2780 | +extern int lxc_assign_network(struct lxc_list *networks, pid_t pid); |
2781 | +extern int lxc_find_gateway_addresses(struct lxc_handler *handler); |
2782 | + |
2783 | +extern int lxc_create_tty(const char *name, struct lxc_conf *conf); |
2784 | +extern void lxc_delete_tty(struct lxc_tty_info *tty_info); |
2785 | + |
2786 | +extern int lxc_clear_config_network(struct lxc_conf *c); |
2787 | +extern int lxc_clear_nic(struct lxc_conf *c, char *key); |
2788 | +extern int lxc_clear_config_caps(struct lxc_conf *c); |
2789 | +extern int lxc_clear_cgroups(struct lxc_conf *c, char *key); |
2790 | +extern int lxc_clear_mount_entries(struct lxc_conf *c); |
2791 | +extern int lxc_clear_hooks(struct lxc_conf *c); |
2792 | + |
2793 | +/* |
2794 | + * Configure the container from inside |
2795 | + */ |
2796 | + |
2797 | +extern int lxc_setup(const char *name, struct lxc_conf *lxc_conf); |
2798 | +#endif |
2799 | |
2800 | === added file '.pc/0220-getitem-per-hook-type/src/lxc/confile.c' |
2801 | --- .pc/0220-getitem-per-hook-type/src/lxc/confile.c 1970-01-01 00:00:00 +0000 |
2802 | +++ .pc/0220-getitem-per-hook-type/src/lxc/confile.c 2012-09-14 20:24:18 +0000 |
2803 | @@ -0,0 +1,1673 @@ |
2804 | +/* |
2805 | + * lxc: linux Container library |
2806 | + * |
2807 | + * (C) Copyright IBM Corp. 2007, 2008 |
2808 | + * |
2809 | + * Authors: |
2810 | + * Daniel Lezcano <dlezcano at fr.ibm.com> |
2811 | + * |
2812 | + * This library is free software; you can redistribute it and/or |
2813 | + * modify it under the terms of the GNU Lesser General Public |
2814 | + * License as published by the Free Software Foundation; either |
2815 | + * version 2.1 of the License, or (at your option) any later version. |
2816 | + * |
2817 | + * This library is distributed in the hope that it will be useful, |
2818 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
2819 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
2820 | + * Lesser General Public License for more details. |
2821 | + * |
2822 | + * You should have received a copy of the GNU Lesser General Public |
2823 | + * License along with this library; if not, write to the Free Software |
2824 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
2825 | + */ |
2826 | +#include <stdio.h> |
2827 | +#include <stdlib.h> |
2828 | +#include <string.h> |
2829 | +#include <unistd.h> |
2830 | +#include <errno.h> |
2831 | +#include <fcntl.h> |
2832 | +#include <pty.h> |
2833 | +#include <sys/stat.h> |
2834 | +#include <sys/types.h> |
2835 | +#include <sys/param.h> |
2836 | +#include <sys/utsname.h> |
2837 | +#include <sys/personality.h> |
2838 | +#include <arpa/inet.h> |
2839 | +#include <netinet/in.h> |
2840 | +#include <net/if.h> |
2841 | + |
2842 | +#include "parse.h" |
2843 | +#include "confile.h" |
2844 | +#include "utils.h" |
2845 | + |
2846 | +#include <lxc/log.h> |
2847 | +#include <lxc/conf.h> |
2848 | +#include "network.h" |
2849 | + |
2850 | +lxc_log_define(lxc_confile, lxc); |
2851 | + |
2852 | +static int config_personality(const char *, char *, struct lxc_conf *); |
2853 | +static int config_pts(const char *, char *, struct lxc_conf *); |
2854 | +static int config_tty(const char *, char *, struct lxc_conf *); |
2855 | +static int config_ttydir(const char *, char *, struct lxc_conf *); |
2856 | +static int config_aa_profile(const char *, char *, struct lxc_conf *); |
2857 | +static int config_cgroup(const char *, char *, struct lxc_conf *); |
2858 | +static int config_mount(const char *, char *, struct lxc_conf *); |
2859 | +static int config_rootfs(const char *, char *, struct lxc_conf *); |
2860 | +static int config_rootfs_mount(const char *, char *, struct lxc_conf *); |
2861 | +static int config_pivotdir(const char *, char *, struct lxc_conf *); |
2862 | +static int config_utsname(const char *, char *, struct lxc_conf *); |
2863 | +static int config_hook(const char *key, char *value, struct lxc_conf *lxc_conf); |
2864 | +static int config_network_type(const char *, char *, struct lxc_conf *); |
2865 | +static int config_network_flags(const char *, char *, struct lxc_conf *); |
2866 | +static int config_network_link(const char *, char *, struct lxc_conf *); |
2867 | +static int config_network_name(const char *, char *, struct lxc_conf *); |
2868 | +static int config_network_veth_pair(const char *, char *, struct lxc_conf *); |
2869 | +static int config_network_macvlan_mode(const char *, char *, struct lxc_conf *); |
2870 | +static int config_network_hwaddr(const char *, char *, struct lxc_conf *); |
2871 | +static int config_network_vlan_id(const char *, char *, struct lxc_conf *); |
2872 | +static int config_network_mtu(const char *, char *, struct lxc_conf *); |
2873 | +static int config_network_ipv4(const char *, char *, struct lxc_conf *); |
2874 | +static int config_network_ipv4_gateway(const char *, char *, struct lxc_conf *); |
2875 | +static int config_network_script(const char *, char *, struct lxc_conf *); |
2876 | +static int config_network_ipv6(const char *, char *, struct lxc_conf *); |
2877 | +static int config_network_ipv6_gateway(const char *, char *, struct lxc_conf *); |
2878 | +static int config_cap_drop(const char *, char *, struct lxc_conf *); |
2879 | +static int config_console(const char *, char *, struct lxc_conf *); |
2880 | +static int config_seccomp(const char *, char *, struct lxc_conf *); |
2881 | +static int config_includefile(const char *, char *, struct lxc_conf *); |
2882 | +static int config_network_nic(const char *, char *, struct lxc_conf *); |
2883 | + |
2884 | +typedef int (*config_cb)(const char *, char *, struct lxc_conf *); |
2885 | + |
2886 | +static struct lxc_config_t config[] = { |
2887 | + |
2888 | + { "lxc.arch", config_personality }, |
2889 | + { "lxc.pts", config_pts }, |
2890 | + { "lxc.tty", config_tty }, |
2891 | + { "lxc.devttydir", config_ttydir }, |
2892 | + { "lxc.aa_profile", config_aa_profile }, |
2893 | + { "lxc.cgroup", config_cgroup }, |
2894 | + { "lxc.mount", config_mount }, |
2895 | + { "lxc.rootfs.mount", config_rootfs_mount }, |
2896 | + { "lxc.rootfs", config_rootfs }, |
2897 | + { "lxc.pivotdir", config_pivotdir }, |
2898 | + { "lxc.utsname", config_utsname }, |
2899 | + { "lxc.hook.pre-start", config_hook }, |
2900 | + { "lxc.hook.pre-mount", config_hook }, |
2901 | + { "lxc.hook.mount", config_hook }, |
2902 | + { "lxc.hook.start", config_hook }, |
2903 | + { "lxc.hook.post-stop", config_hook }, |
2904 | + { "lxc.network.type", config_network_type }, |
2905 | + { "lxc.network.flags", config_network_flags }, |
2906 | + { "lxc.network.link", config_network_link }, |
2907 | + { "lxc.network.name", config_network_name }, |
2908 | + { "lxc.network.macvlan.mode", config_network_macvlan_mode }, |
2909 | + { "lxc.network.veth.pair", config_network_veth_pair }, |
2910 | + { "lxc.network.script.up", config_network_script }, |
2911 | + { "lxc.network.hwaddr", config_network_hwaddr }, |
2912 | + { "lxc.network.mtu", config_network_mtu }, |
2913 | + { "lxc.network.vlan.id", config_network_vlan_id }, |
2914 | + { "lxc.network.ipv4.gateway", config_network_ipv4_gateway }, |
2915 | + { "lxc.network.ipv4", config_network_ipv4 }, |
2916 | + { "lxc.network.ipv6.gateway", config_network_ipv6_gateway }, |
2917 | + { "lxc.network.ipv6", config_network_ipv6 }, |
2918 | + /* config_network_nic must come after all other 'lxc.network.*' entries */ |
2919 | + { "lxc.network.", config_network_nic }, |
2920 | + { "lxc.cap.drop", config_cap_drop }, |
2921 | + { "lxc.console", config_console }, |
2922 | + { "lxc.seccomp", config_seccomp }, |
2923 | + { "lxc.include", config_includefile }, |
2924 | +}; |
2925 | + |
2926 | +static const size_t config_size = sizeof(config)/sizeof(struct lxc_config_t); |
2927 | + |
2928 | +extern struct lxc_config_t *lxc_getconfig(const char *key) |
2929 | +{ |
2930 | + int i; |
2931 | + |
2932 | + for (i = 0; i < config_size; i++) |
2933 | + if (!strncmp(config[i].name, key, |
2934 | + strlen(config[i].name))) |
2935 | + return &config[i]; |
2936 | + return NULL; |
2937 | +} |
2938 | + |
2939 | +#define strprint(str, inlen, ...) \ |
2940 | + do { \ |
2941 | + len = snprintf(str, inlen, ##__VA_ARGS__); \ |
2942 | + if (len < 0) { SYSERROR("snprintf"); return -1; }; \ |
2943 | + fulllen += len; \ |
2944 | + if (inlen > 0) { \ |
2945 | + if (str) str += len; \ |
2946 | + inlen -= len; \ |
2947 | + if (inlen < 0) inlen = 0; \ |
2948 | + } \ |
2949 | + } while (0); |
2950 | + |
2951 | +int lxc_listconfigs(char *retv, int inlen) |
2952 | +{ |
2953 | + int i, fulllen = 0, len; |
2954 | + |
2955 | + if (!retv) |
2956 | + inlen = 0; |
2957 | + else |
2958 | + memset(retv, 0, inlen); |
2959 | + for (i = 0; i < config_size; i++) { |
2960 | + char *s = config[i].name; |
2961 | + if (s[strlen(s)-1] == '.') |
2962 | + continue; |
2963 | + strprint(retv, inlen, "%s\n", s); |
2964 | + } |
2965 | + return fulllen; |
2966 | +} |
2967 | + |
2968 | +/* |
2969 | + * config entry is something like "lxc.network.0.ipv4" |
2970 | + * the key 'lxc.network.' was found. So we make sure next |
2971 | + * comes an integer, find the right callback (by rewriting |
2972 | + * the key), and call it. |
2973 | + */ |
2974 | +static int config_network_nic(const char *key, char *value, |
2975 | + struct lxc_conf *lxc_conf) |
2976 | +{ |
2977 | + char *copy = strdup(key), *p; |
2978 | + int ret = -1; |
2979 | + struct lxc_config_t *config; |
2980 | + |
2981 | + if (!copy) { |
2982 | + SYSERROR("failed to allocate memory"); |
2983 | + return -1; |
2984 | + } |
2985 | + /* |
2986 | + * ok we know that to get here we've got "lxc.network." |
2987 | + * and it isn't any of the other network entries. So |
2988 | + * after the second . should come an integer (# of defined |
2989 | + * nic) followed by a valid entry. |
2990 | + */ |
2991 | + if (*(key+12) < '0' || *(key+12) > '9') |
2992 | + goto out; |
2993 | + p = index(key+12, '.'); |
2994 | + if (!p) |
2995 | + goto out; |
2996 | + strcpy(copy+12, p+1); |
2997 | + config = lxc_getconfig(copy); |
2998 | + if (!config) { |
2999 | + ERROR("unknown key %s", key); |
3000 | + goto out; |
3001 | + } |
3002 | + ret = config->cb(key, value, lxc_conf); |
3003 | + |
3004 | +out: |
3005 | + free(copy); |
3006 | + return ret; |
3007 | +} |
3008 | + |
3009 | +static int config_network_type(const char *key, char *value, |
3010 | + struct lxc_conf *lxc_conf) |
3011 | +{ |
3012 | + struct lxc_list *network = &lxc_conf->network; |
3013 | + struct lxc_netdev *netdev; |
3014 | + struct lxc_list *list; |
3015 | + |
3016 | + netdev = malloc(sizeof(*netdev)); |
3017 | + if (!netdev) { |
3018 | + SYSERROR("failed to allocate memory"); |
3019 | + return -1; |
3020 | + } |
3021 | + |
3022 | + memset(netdev, 0, sizeof(*netdev)); |
3023 | + lxc_list_init(&netdev->ipv4); |
3024 | + lxc_list_init(&netdev->ipv6); |
3025 | + |
3026 | + list = malloc(sizeof(*list)); |
3027 | + if (!list) { |
3028 | + SYSERROR("failed to allocate memory"); |
3029 | + return -1; |
3030 | + } |
3031 | + |
3032 | + lxc_list_init(list); |
3033 | + list->elem = netdev; |
3034 | + |
3035 | + lxc_list_add_tail(network, list); |
3036 | + |
3037 | + if (!strcmp(value, "veth")) |
3038 | + netdev->type = LXC_NET_VETH; |
3039 | + else if (!strcmp(value, "macvlan")) |
3040 | + netdev->type = LXC_NET_MACVLAN; |
3041 | + else if (!strcmp(value, "vlan")) |
3042 | + netdev->type = LXC_NET_VLAN; |
3043 | + else if (!strcmp(value, "phys")) |
3044 | + netdev->type = LXC_NET_PHYS; |
3045 | + else if (!strcmp(value, "empty")) |
3046 | + netdev->type = LXC_NET_EMPTY; |
3047 | + else { |
3048 | + ERROR("invalid network type %s", value); |
3049 | + return -1; |
3050 | + } |
3051 | + return 0; |
3052 | +} |
3053 | + |
3054 | +static int config_ip_prefix(struct in_addr *addr) |
3055 | +{ |
3056 | + if (IN_CLASSA(addr->s_addr)) |
3057 | + return 32 - IN_CLASSA_NSHIFT; |
3058 | + if (IN_CLASSB(addr->s_addr)) |
3059 | + return 32 - IN_CLASSB_NSHIFT; |
3060 | + if (IN_CLASSC(addr->s_addr)) |
3061 | + return 32 - IN_CLASSC_NSHIFT; |
3062 | + |
3063 | + return 0; |
3064 | +} |
3065 | + |
3066 | +/* |
3067 | + * if you have p="lxc.network.0.link", pass it p+12 |
3068 | + * to get back '0' (the index of the nic) |
3069 | + */ |
3070 | +static int get_network_netdev_idx(const char *key) |
3071 | +{ |
3072 | + int ret, idx; |
3073 | + |
3074 | + if (*key < '0' || *key > '9') |
3075 | + return -1; |
3076 | + ret = sscanf(key, "%d", &idx); |
3077 | + if (ret != 1) |
3078 | + return -1; |
3079 | + return idx; |
3080 | +} |
3081 | + |
3082 | +/* |
3083 | + * if you have p="lxc.network.0", pass this p+12 and it will return |
3084 | + * the netdev of the first configured nic |
3085 | + */ |
3086 | +static struct lxc_netdev *get_netdev_from_key(const char *key, |
3087 | + struct lxc_list *network) |
3088 | +{ |
3089 | + int i = 0, idx = get_network_netdev_idx(key); |
3090 | + struct lxc_netdev *netdev = NULL; |
3091 | + struct lxc_list *it; |
3092 | + if (idx == -1) |
3093 | + return NULL; |
3094 | + lxc_list_for_each(it, network) { |
3095 | + if (idx == i++) { |
3096 | + netdev = it->elem; |
3097 | + break; |
3098 | + } |
3099 | + } |
3100 | + return netdev; |
3101 | +} |
3102 | + |
3103 | +extern int lxc_list_nicconfigs(struct lxc_conf *c, char *key, char *retv, int inlen) |
3104 | +{ |
3105 | + struct lxc_netdev *netdev; |
3106 | + int fulllen = 0, len; |
3107 | + |
3108 | + netdev = get_netdev_from_key(key+12, &c->network); |
3109 | + if (!netdev) |
3110 | + return -1; |
3111 | + |
3112 | + if (!retv) |
3113 | + inlen = 0; |
3114 | + else |
3115 | + memset(retv, 0, inlen); |
3116 | + |
3117 | + strprint(retv, inlen, "script.up\n"); |
3118 | + if (netdev->type != LXC_NET_EMPTY) { |
3119 | + strprint(retv, inlen, "flags\n"); |
3120 | + strprint(retv, inlen, "link\n"); |
3121 | + strprint(retv, inlen, "name\n"); |
3122 | + strprint(retv, inlen, "hwaddr\n"); |
3123 | + strprint(retv, inlen, "mtu\n"); |
3124 | + strprint(retv, inlen, "ipv6\n"); |
3125 | + strprint(retv, inlen, "ipv6_gateway\n"); |
3126 | + strprint(retv, inlen, "ipv4\n"); |
3127 | + strprint(retv, inlen, "ipv4_gateway\n"); |
3128 | + } |
3129 | + switch(netdev->type) { |
3130 | + case LXC_NET_VETH: |
3131 | + strprint(retv, inlen, "veth.pair\n"); |
3132 | + break; |
3133 | + case LXC_NET_MACVLAN: |
3134 | + strprint(retv, inlen, "macvlan.mode\n"); |
3135 | + break; |
3136 | + case LXC_NET_VLAN: |
3137 | + strprint(retv, inlen, "vlan.id\n"); |
3138 | + break; |
3139 | + case LXC_NET_PHYS: |
3140 | + break; |
3141 | + } |
3142 | + return fulllen; |
3143 | +} |
3144 | + |
3145 | +static struct lxc_netdev *network_netdev(const char *key, const char *value, |
3146 | + struct lxc_list *network) |
3147 | +{ |
3148 | + struct lxc_netdev *netdev = NULL; |
3149 | + |
3150 | + if (lxc_list_empty(network)) { |
3151 | + ERROR("network is not created for '%s' = '%s' option", |
3152 | + key, value); |
3153 | + return NULL; |
3154 | + } |
3155 | + |
3156 | + if (get_network_netdev_idx(key+12) == -1) |
3157 | + netdev = lxc_list_last_elem(network); |
3158 | + else |
3159 | + netdev = get_netdev_from_key(key+12, network); |
3160 | + |
3161 | + if (!netdev) { |
3162 | + ERROR("no network device defined for '%s' = '%s' option", |
3163 | + key, value); |
3164 | + return NULL; |
3165 | + } |
3166 | + |
3167 | + return netdev; |
3168 | +} |
3169 | + |
3170 | +static int network_ifname(char **valuep, char *value) |
3171 | +{ |
3172 | + if (strlen(value) >= IFNAMSIZ) { |
3173 | + ERROR("invalid interface name: %s", value); |
3174 | + return -1; |
3175 | + } |
3176 | + |
3177 | + *valuep = strdup(value); |
3178 | + if (!*valuep) { |
3179 | + ERROR("failed to dup string '%s'", value); |
3180 | + return -1; |
3181 | + } |
3182 | + |
3183 | + return 0; |
3184 | +} |
3185 | + |
3186 | +#ifndef MACVLAN_MODE_PRIVATE |
3187 | +# define MACVLAN_MODE_PRIVATE 1 |
3188 | +#endif |
3189 | + |
3190 | +#ifndef MACVLAN_MODE_VEPA |
3191 | +# define MACVLAN_MODE_VEPA 2 |
3192 | +#endif |
3193 | + |
3194 | +#ifndef MACVLAN_MODE_BRIDGE |
3195 | +# define MACVLAN_MODE_BRIDGE 4 |
3196 | +#endif |
3197 | + |
3198 | +static int macvlan_mode(int *valuep, char *value) |
3199 | +{ |
3200 | + struct mc_mode { |
3201 | + char *name; |
3202 | + int mode; |
3203 | + } m[] = { |
3204 | + { "private", MACVLAN_MODE_PRIVATE }, |
3205 | + { "vepa", MACVLAN_MODE_VEPA }, |
3206 | + { "bridge", MACVLAN_MODE_BRIDGE }, |
3207 | + }; |
3208 | + |
3209 | + int i; |
3210 | + |
3211 | + for (i = 0; i < sizeof(m)/sizeof(m[0]); i++) { |
3212 | + if (strcmp(m[i].name, value)) |
3213 | + continue; |
3214 | + |
3215 | + *valuep = m[i].mode; |
3216 | + return 0; |
3217 | + } |
3218 | + |
3219 | + return -1; |
3220 | +} |
3221 | + |
3222 | +static int config_network_flags(const char *key, char *value, |
3223 | + struct lxc_conf *lxc_conf) |
3224 | +{ |
3225 | + struct lxc_netdev *netdev; |
3226 | + |
3227 | + netdev = network_netdev(key, value, &lxc_conf->network); |
3228 | + if (!netdev) |
3229 | + return -1; |
3230 | + |
3231 | + netdev->flags |= IFF_UP; |
3232 | + |
3233 | + return 0; |
3234 | +} |
3235 | + |
3236 | +static int config_network_link(const char *key, char *value, |
3237 | + struct lxc_conf *lxc_conf) |
3238 | +{ |
3239 | + struct lxc_netdev *netdev; |
3240 | + |
3241 | + netdev = network_netdev(key, value, &lxc_conf->network); |
3242 | + if (!netdev) |
3243 | + return -1; |
3244 | + |
3245 | + return network_ifname(&netdev->link, value); |
3246 | +} |
3247 | + |
3248 | +static int config_network_name(const char *key, char *value, |
3249 | + struct lxc_conf *lxc_conf) |
3250 | +{ |
3251 | + struct lxc_netdev *netdev; |
3252 | + |
3253 | + netdev = network_netdev(key, value, &lxc_conf->network); |
3254 | + if (!netdev) |
3255 | + return -1; |
3256 | + |
3257 | + return network_ifname(&netdev->name, value); |
3258 | +} |
3259 | + |
3260 | +static int config_network_veth_pair(const char *key, char *value, |
3261 | + struct lxc_conf *lxc_conf) |
3262 | +{ |
3263 | + struct lxc_netdev *netdev; |
3264 | + |
3265 | + netdev = network_netdev(key, value, &lxc_conf->network); |
3266 | + if (!netdev) |
3267 | + return -1; |
3268 | + |
3269 | + return network_ifname(&netdev->priv.veth_attr.pair, value); |
3270 | +} |
3271 | + |
3272 | +static int config_network_macvlan_mode(const char *key, char *value, |
3273 | + struct lxc_conf *lxc_conf) |
3274 | +{ |
3275 | + struct lxc_netdev *netdev; |
3276 | + |
3277 | + netdev = network_netdev(key, value, &lxc_conf->network); |
3278 | + if (!netdev) |
3279 | + return -1; |
3280 | + |
3281 | + return macvlan_mode(&netdev->priv.macvlan_attr.mode, value); |
3282 | +} |
3283 | + |
3284 | +static int config_network_hwaddr(const char *key, char *value, |
3285 | + struct lxc_conf *lxc_conf) |
3286 | +{ |
3287 | + struct lxc_netdev *netdev; |
3288 | + |
3289 | + netdev = network_netdev(key, value, &lxc_conf->network); |
3290 | + if (!netdev) |
3291 | + return -1; |
3292 | + |
3293 | + netdev->hwaddr = strdup(value); |
3294 | + if (!netdev->hwaddr) { |
3295 | + SYSERROR("failed to dup string '%s'", value); |
3296 | + return -1; |
3297 | + } |
3298 | + |
3299 | + return 0; |
3300 | +} |
3301 | + |
3302 | +static int config_network_vlan_id(const char *key, char *value, |
3303 | + struct lxc_conf *lxc_conf) |
3304 | +{ |
3305 | + struct lxc_netdev *netdev; |
3306 | + |
3307 | + netdev = network_netdev(key, value, &lxc_conf->network); |
3308 | + if (!netdev) |
3309 | + return -1; |
3310 | + |
3311 | + if (get_u16(&netdev->priv.vlan_attr.vid, value, 0)) |
3312 | + return -1; |
3313 | + |
3314 | + return 0; |
3315 | +} |
3316 | + |
3317 | +static int config_network_mtu(const char *key, char *value, |
3318 | + struct lxc_conf *lxc_conf) |
3319 | +{ |
3320 | + struct lxc_netdev *netdev; |
3321 | + |
3322 | + netdev = network_netdev(key, value, &lxc_conf->network); |
3323 | + if (!netdev) |
3324 | + return -1; |
3325 | + |
3326 | + netdev->mtu = strdup(value); |
3327 | + if (!netdev->mtu) { |
3328 | + SYSERROR("failed to dup string '%s'", value); |
3329 | + return -1; |
3330 | + } |
3331 | + |
3332 | + return 0; |
3333 | +} |
3334 | + |
3335 | +static int config_network_ipv4(const char *key, char *value, |
3336 | + struct lxc_conf *lxc_conf) |
3337 | +{ |
3338 | + struct lxc_netdev *netdev; |
3339 | + struct lxc_inetdev *inetdev; |
3340 | + struct lxc_list *list; |
3341 | + char *cursor, *slash, *addr = NULL, *bcast = NULL, *prefix = NULL; |
3342 | + |
3343 | + netdev = network_netdev(key, value, &lxc_conf->network); |
3344 | + if (!netdev) |
3345 | + return -1; |
3346 | + |
3347 | + inetdev = malloc(sizeof(*inetdev)); |
3348 | + if (!inetdev) { |
3349 | + SYSERROR("failed to allocate ipv4 address"); |
3350 | + return -1; |
3351 | + } |
3352 | + memset(inetdev, 0, sizeof(*inetdev)); |
3353 | + |
3354 | + list = malloc(sizeof(*list)); |
3355 | + if (!list) { |
3356 | + SYSERROR("failed to allocate memory"); |
3357 | + return -1; |
3358 | + } |
3359 | + |
3360 | + lxc_list_init(list); |
3361 | + list->elem = inetdev; |
3362 | + |
3363 | + addr = value; |
3364 | + |
3365 | + cursor = strstr(addr, " "); |
3366 | + if (cursor) { |
3367 | + *cursor = '\0'; |
3368 | + bcast = cursor + 1; |
3369 | + } |
3370 | + |
3371 | + slash = strstr(addr, "/"); |
3372 | + if (slash) { |
3373 | + *slash = '\0'; |
3374 | + prefix = slash + 1; |
3375 | + } |
3376 | + |
3377 | + if (!addr) { |
3378 | + ERROR("no address specified"); |
3379 | + return -1; |
3380 | + } |
3381 | + |
3382 | + if (!inet_pton(AF_INET, addr, &inetdev->addr)) { |
3383 | + SYSERROR("invalid ipv4 address: %s", value); |
3384 | + return -1; |
3385 | + } |
3386 | + |
3387 | + if (bcast && !inet_pton(AF_INET, bcast, &inetdev->bcast)) { |
3388 | + SYSERROR("invalid ipv4 broadcast address: %s", value); |
3389 | + return -1; |
3390 | + } |
3391 | + |
3392 | + /* no prefix specified, determine it from the network class */ |
3393 | + inetdev->prefix = prefix ? atoi(prefix) : |
3394 | + config_ip_prefix(&inetdev->addr); |
3395 | + |
3396 | + /* if no broadcast address, let compute one from the |
3397 | + * prefix and address |
3398 | + */ |
3399 | + if (!bcast) { |
3400 | + inetdev->bcast.s_addr = inetdev->addr.s_addr; |
3401 | + inetdev->bcast.s_addr |= |
3402 | + htonl(INADDR_BROADCAST >> inetdev->prefix); |
3403 | + } |
3404 | + |
3405 | + lxc_list_add(&netdev->ipv4, list); |
3406 | + |
3407 | + return 0; |
3408 | +} |
3409 | + |
3410 | +static int config_network_ipv4_gateway(const char *key, char *value, |
3411 | + struct lxc_conf *lxc_conf) |
3412 | +{ |
3413 | + struct lxc_netdev *netdev; |
3414 | + struct in_addr *gw; |
3415 | + |
3416 | + netdev = network_netdev(key, value, &lxc_conf->network); |
3417 | + if (!netdev) |
3418 | + return -1; |
3419 | + |
3420 | + gw = malloc(sizeof(*gw)); |
3421 | + if (!gw) { |
3422 | + SYSERROR("failed to allocate ipv4 gateway address"); |
3423 | + return -1; |
3424 | + } |
3425 | + |
3426 | + if (!value) { |
3427 | + ERROR("no ipv4 gateway address specified"); |
3428 | + return -1; |
3429 | + } |
3430 | + |
3431 | + if (!strcmp(value, "auto")) { |
3432 | + netdev->ipv4_gateway = NULL; |
3433 | + netdev->ipv4_gateway_auto = true; |
3434 | + } else { |
3435 | + if (!inet_pton(AF_INET, value, gw)) { |
3436 | + SYSERROR("invalid ipv4 gateway address: %s", value); |
3437 | + return -1; |
3438 | + } |
3439 | + |
3440 | + netdev->ipv4_gateway = gw; |
3441 | + netdev->ipv4_gateway_auto = false; |
3442 | + } |
3443 | + |
3444 | + return 0; |
3445 | +} |
3446 | + |
3447 | +static int config_network_ipv6(const char *key, char *value, |
3448 | + struct lxc_conf *lxc_conf) |
3449 | +{ |
3450 | + struct lxc_netdev *netdev; |
3451 | + struct lxc_inet6dev *inet6dev; |
3452 | + struct lxc_list *list; |
3453 | + char *slash; |
3454 | + char *netmask; |
3455 | + |
3456 | + netdev = network_netdev(key, value, &lxc_conf->network); |
3457 | + if (!netdev) |
3458 | + return -1; |
3459 | + |
3460 | + inet6dev = malloc(sizeof(*inet6dev)); |
3461 | + if (!inet6dev) { |
3462 | + SYSERROR("failed to allocate ipv6 address"); |
3463 | + return -1; |
3464 | + } |
3465 | + memset(inet6dev, 0, sizeof(*inet6dev)); |
3466 | + |
3467 | + list = malloc(sizeof(*list)); |
3468 | + if (!list) { |
3469 | + SYSERROR("failed to allocate memory"); |
3470 | + return -1; |
3471 | + } |
3472 | + |
3473 | + lxc_list_init(list); |
3474 | + list->elem = inet6dev; |
3475 | + |
3476 | + inet6dev->prefix = 64; |
3477 | + slash = strstr(value, "/"); |
3478 | + if (slash) { |
3479 | + *slash = '\0'; |
3480 | + netmask = slash + 1; |
3481 | + inet6dev->prefix = atoi(netmask); |
3482 | + } |
3483 | + |
3484 | + if (!inet_pton(AF_INET6, value, &inet6dev->addr)) { |
3485 | + SYSERROR("invalid ipv6 address: %s", value); |
3486 | + return -1; |
3487 | + } |
3488 | + |
3489 | + lxc_list_add(&netdev->ipv6, list); |
3490 | + |
3491 | + return 0; |
3492 | +} |
3493 | + |
3494 | +static int config_network_ipv6_gateway(const char *key, char *value, |
3495 | + struct lxc_conf *lxc_conf) |
3496 | +{ |
3497 | + struct lxc_netdev *netdev; |
3498 | + struct in6_addr *gw; |
3499 | + |
3500 | + netdev = network_netdev(key, value, &lxc_conf->network); |
3501 | + if (!netdev) |
3502 | + return -1; |
3503 | + |
3504 | + gw = malloc(sizeof(*gw)); |
3505 | + if (!gw) { |
3506 | + SYSERROR("failed to allocate ipv6 gateway address"); |
3507 | + return -1; |
3508 | + } |
3509 | + |
3510 | + if (!value) { |
3511 | + ERROR("no ipv6 gateway address specified"); |
3512 | + return -1; |
3513 | + } |
3514 | + |
3515 | + if (!strcmp(value, "auto")) { |
3516 | + netdev->ipv6_gateway = NULL; |
3517 | + netdev->ipv6_gateway_auto = true; |
3518 | + } else { |
3519 | + if (!inet_pton(AF_INET6, value, gw)) { |
3520 | + SYSERROR("invalid ipv6 gateway address: %s", value); |
3521 | + return -1; |
3522 | + } |
3523 | + |
3524 | + netdev->ipv6_gateway = gw; |
3525 | + netdev->ipv6_gateway_auto = false; |
3526 | + } |
3527 | + |
3528 | + return 0; |
3529 | +} |
3530 | + |
3531 | +static int config_network_script(const char *key, char *value, |
3532 | + struct lxc_conf *lxc_conf) |
3533 | +{ |
3534 | + struct lxc_netdev *netdev; |
3535 | + |
3536 | + netdev = network_netdev(key, value, &lxc_conf->network); |
3537 | + if (!netdev) |
3538 | + return -1; |
3539 | + |
3540 | + char *copy = strdup(value); |
3541 | + if (!copy) { |
3542 | + SYSERROR("failed to dup string '%s'", value); |
3543 | + return -1; |
3544 | + } |
3545 | + if (strstr(key, "script.up") != NULL) { |
3546 | + netdev->upscript = copy; |
3547 | + return 0; |
3548 | + } |
3549 | + SYSERROR("Unknown key: %s", key); |
3550 | + free(copy); |
3551 | + return -1; |
3552 | +} |
3553 | + |
3554 | +static int add_hook(struct lxc_conf *lxc_conf, int which, char *hook) |
3555 | +{ |
3556 | + struct lxc_list *hooklist; |
3557 | + |
3558 | + hooklist = malloc(sizeof(*hooklist)); |
3559 | + if (!hooklist) { |
3560 | + free(hook); |
3561 | + return -1; |
3562 | + } |
3563 | + hooklist->elem = hook; |
3564 | + lxc_list_add_tail(&lxc_conf->hooks[which], hooklist); |
3565 | + return 0; |
3566 | +} |
3567 | + |
3568 | +static int config_seccomp(const char *key, char *value, |
3569 | + struct lxc_conf *lxc_conf) |
3570 | +{ |
3571 | + char *path; |
3572 | + |
3573 | + if (lxc_conf->seccomp) { |
3574 | + ERROR("seccomp already defined"); |
3575 | + return -1; |
3576 | + } |
3577 | + path = strdup(value); |
3578 | + if (!path) { |
3579 | + SYSERROR("failed to strdup '%s': %m", value); |
3580 | + return -1; |
3581 | + } |
3582 | + |
3583 | + lxc_conf->seccomp = path; |
3584 | + |
3585 | + return 0; |
3586 | +} |
3587 | + |
3588 | +static int config_hook(const char *key, char *value, |
3589 | + struct lxc_conf *lxc_conf) |
3590 | +{ |
3591 | + char *copy = strdup(value); |
3592 | + if (!copy) { |
3593 | + SYSERROR("failed to dup string '%s'", value); |
3594 | + return -1; |
3595 | + } |
3596 | + if (strcmp(key, "lxc.hook.pre-start") == 0) |
3597 | + return add_hook(lxc_conf, LXCHOOK_PRESTART, copy); |
3598 | + else if (strcmp(key, "lxc.hook.pre-mount") == 0) |
3599 | + return add_hook(lxc_conf, LXCHOOK_PREMOUNT, copy); |
3600 | + else if (strcmp(key, "lxc.hook.mount") == 0) |
3601 | + return add_hook(lxc_conf, LXCHOOK_MOUNT, copy); |
3602 | + else if (strcmp(key, "lxc.hook.start") == 0) |
3603 | + return add_hook(lxc_conf, LXCHOOK_START, copy); |
3604 | + else if (strcmp(key, "lxc.hook.post-stop") == 0) |
3605 | + return add_hook(lxc_conf, LXCHOOK_POSTSTOP, copy); |
3606 | + SYSERROR("Unknown key: %s", key); |
3607 | + free(copy); |
3608 | + return -1; |
3609 | +} |
3610 | + |
3611 | +static int config_personality(const char *key, char *value, |
3612 | + struct lxc_conf *lxc_conf) |
3613 | +{ |
3614 | + signed long personality = lxc_config_parse_arch(value); |
3615 | + |
3616 | + if (personality >= 0) |
3617 | + lxc_conf->personality = personality; |
3618 | + else |
3619 | + WARN("unsupported personality '%s'", value); |
3620 | + |
3621 | + return 0; |
3622 | +} |
3623 | + |
3624 | +static int config_pts(const char *key, char *value, struct lxc_conf *lxc_conf) |
3625 | +{ |
3626 | + int maxpts = atoi(value); |
3627 | + |
3628 | + lxc_conf->pts = maxpts; |
3629 | + |
3630 | + return 0; |
3631 | +} |
3632 | + |
3633 | +static int config_tty(const char *key, char *value, struct lxc_conf *lxc_conf) |
3634 | +{ |
3635 | + int nbtty = atoi(value); |
3636 | + |
3637 | + lxc_conf->tty = nbtty; |
3638 | + |
3639 | + return 0; |
3640 | +} |
3641 | + |
3642 | +static int config_ttydir(const char *key, char *value, |
3643 | + struct lxc_conf *lxc_conf) |
3644 | +{ |
3645 | + char *path; |
3646 | + |
3647 | + if (!value || strlen(value) == 0) |
3648 | + return 0; |
3649 | + path = strdup(value); |
3650 | + if (!path) { |
3651 | + SYSERROR("failed to strdup '%s': %m", value); |
3652 | + return -1; |
3653 | + } |
3654 | + |
3655 | + lxc_conf->ttydir = path; |
3656 | + |
3657 | + return 0; |
3658 | +} |
3659 | + |
3660 | +static int config_aa_profile(const char *key, char *value, |
3661 | + struct lxc_conf *lxc_conf) |
3662 | +{ |
3663 | + char *path; |
3664 | + |
3665 | + if (!value || strlen(value) == 0) |
3666 | + return 0; |
3667 | + path = strdup(value); |
3668 | + if (!path) { |
3669 | + SYSERROR("failed to strdup '%s': %m", value); |
3670 | + return -1; |
3671 | + } |
3672 | + |
3673 | + lxc_conf->aa_profile = path; |
3674 | + |
3675 | + return 0; |
3676 | +} |
3677 | + |
3678 | +static int config_cgroup(const char *key, char *value, struct lxc_conf *lxc_conf) |
3679 | +{ |
3680 | + char *token = "lxc.cgroup."; |
3681 | + char *subkey; |
3682 | + struct lxc_list *cglist = NULL; |
3683 | + struct lxc_cgroup *cgelem = NULL; |
3684 | + |
3685 | + subkey = strstr(key, token); |
3686 | + |
3687 | + if (!subkey) |
3688 | + return -1; |
3689 | + |
3690 | + if (!strlen(subkey)) |
3691 | + return -1; |
3692 | + |
3693 | + if (strlen(subkey) == strlen(token)) |
3694 | + return -1; |
3695 | + |
3696 | + subkey += strlen(token); |
3697 | + |
3698 | + cglist = malloc(sizeof(*cglist)); |
3699 | + if (!cglist) |
3700 | + goto out; |
3701 | + |
3702 | + cgelem = malloc(sizeof(*cgelem)); |
3703 | + if (!cgelem) |
3704 | + goto out; |
3705 | + memset(cgelem, 0, sizeof(*cgelem)); |
3706 | + |
3707 | + cgelem->subsystem = strdup(subkey); |
3708 | + cgelem->value = strdup(value); |
3709 | + |
3710 | + if (!cgelem->subsystem || !cgelem->value) |
3711 | + goto out; |
3712 | + |
3713 | + cglist->elem = cgelem; |
3714 | + |
3715 | + lxc_list_add_tail(&lxc_conf->cgroup, cglist); |
3716 | + |
3717 | + return 0; |
3718 | + |
3719 | +out: |
3720 | + if (cglist) |
3721 | + free(cglist); |
3722 | + |
3723 | + if (cgelem) { |
3724 | + if (cgelem->subsystem) |
3725 | + free(cgelem->subsystem); |
3726 | + |
3727 | + if (cgelem->value) |
3728 | + free(cgelem->value); |
3729 | + |
3730 | + free(cgelem); |
3731 | + } |
3732 | + |
3733 | + return -1; |
3734 | +} |
3735 | + |
3736 | +static int config_fstab(const char *key, char *value, struct lxc_conf *lxc_conf) |
3737 | +{ |
3738 | + if (strlen(value) >= MAXPATHLEN) { |
3739 | + ERROR("%s path is too long", value); |
3740 | + return -1; |
3741 | + } |
3742 | + |
3743 | + lxc_conf->fstab = strdup(value); |
3744 | + if (!lxc_conf->fstab) { |
3745 | + SYSERROR("failed to duplicate string %s", value); |
3746 | + return -1; |
3747 | + } |
3748 | + |
3749 | + return 0; |
3750 | +} |
3751 | + |
3752 | +static int config_mount(const char *key, char *value, struct lxc_conf *lxc_conf) |
3753 | +{ |
3754 | + char *fstab_token = "lxc.mount"; |
3755 | + char *token = "lxc.mount.entry"; |
3756 | + char *subkey; |
3757 | + char *mntelem; |
3758 | + struct lxc_list *mntlist; |
3759 | + |
3760 | + subkey = strstr(key, token); |
3761 | + |
3762 | + if (!subkey) { |
3763 | + subkey = strstr(key, fstab_token); |
3764 | + |
3765 | + if (!subkey) |
3766 | + return -1; |
3767 | + |
3768 | + return config_fstab(key, value, lxc_conf); |
3769 | + } |
3770 | + |
3771 | + if (!strlen(subkey)) |
3772 | + return -1; |
3773 | + |
3774 | + mntlist = malloc(sizeof(*mntlist)); |
3775 | + if (!mntlist) |
3776 | + return -1; |
3777 | + |
3778 | + mntelem = strdup(value); |
3779 | + if (!mntelem) |
3780 | + return -1; |
3781 | + mntlist->elem = mntelem; |
3782 | + |
3783 | + lxc_list_add_tail(&lxc_conf->mount_list, mntlist); |
3784 | + |
3785 | + return 0; |
3786 | +} |
3787 | + |
3788 | +static int config_cap_drop(const char *key, char *value, |
3789 | + struct lxc_conf *lxc_conf) |
3790 | +{ |
3791 | + char *dropcaps, *sptr, *token; |
3792 | + struct lxc_list *droplist; |
3793 | + int ret = -1; |
3794 | + |
3795 | + if (!strlen(value)) |
3796 | + return -1; |
3797 | + |
3798 | + dropcaps = strdup(value); |
3799 | + if (!dropcaps) { |
3800 | + SYSERROR("failed to dup '%s'", value); |
3801 | + return -1; |
3802 | + } |
3803 | + |
3804 | + /* in case several capability drop is specified in a single line |
3805 | + * split these caps in a single element for the list */ |
3806 | + for (;;) { |
3807 | + token = strtok_r(dropcaps, " \t", &sptr); |
3808 | + if (!token) { |
3809 | + ret = 0; |
3810 | + break; |
3811 | + } |
3812 | + dropcaps = NULL; |
3813 | + |
3814 | + droplist = malloc(sizeof(*droplist)); |
3815 | + if (!droplist) { |
3816 | + SYSERROR("failed to allocate drop list"); |
3817 | + break; |
3818 | + } |
3819 | + |
3820 | + /* note - i do believe we're losing memory here, |
3821 | + note that token is already pointing into dropcaps |
3822 | + which is strdup'd. we never free that bit. |
3823 | + */ |
3824 | + droplist->elem = strdup(token); |
3825 | + if (!droplist->elem) { |
3826 | + SYSERROR("failed to dup '%s'", token); |
3827 | + free(droplist); |
3828 | + break; |
3829 | + } |
3830 | + |
3831 | + lxc_list_add_tail(&lxc_conf->caps, droplist); |
3832 | + } |
3833 | + |
3834 | + free(dropcaps); |
3835 | + |
3836 | + return ret; |
3837 | +} |
3838 | + |
3839 | +static int config_console(const char *key, char *value, |
3840 | + struct lxc_conf *lxc_conf) |
3841 | +{ |
3842 | + char *path; |
3843 | + |
3844 | + path = strdup(value); |
3845 | + if (!path) { |
3846 | + SYSERROR("failed to strdup '%s': %m", value); |
3847 | + return -1; |
3848 | + } |
3849 | + |
3850 | + lxc_conf->console.path = path; |
3851 | + |
3852 | + return 0; |
3853 | +} |
3854 | + |
3855 | +static int config_includefile(const char *key, char *value, |
3856 | + struct lxc_conf *lxc_conf) |
3857 | +{ |
3858 | + return lxc_config_read(value, lxc_conf); |
3859 | +} |
3860 | + |
3861 | +static int config_rootfs(const char *key, char *value, struct lxc_conf *lxc_conf) |
3862 | +{ |
3863 | + if (strlen(value) >= MAXPATHLEN) { |
3864 | + ERROR("%s path is too long", value); |
3865 | + return -1; |
3866 | + } |
3867 | + |
3868 | + lxc_conf->rootfs.path = strdup(value); |
3869 | + if (!lxc_conf->rootfs.path) { |
3870 | + SYSERROR("failed to duplicate string %s", value); |
3871 | + return -1; |
3872 | + } |
3873 | + |
3874 | + return 0; |
3875 | +} |
3876 | + |
3877 | +static int config_rootfs_mount(const char *key, char *value, struct lxc_conf *lxc_conf) |
3878 | +{ |
3879 | + if (strlen(value) >= MAXPATHLEN) { |
3880 | + ERROR("%s path is too long", value); |
3881 | + return -1; |
3882 | + } |
3883 | + |
3884 | + lxc_conf->rootfs.mount = strdup(value); |
3885 | + if (!lxc_conf->rootfs.mount) { |
3886 | + SYSERROR("failed to duplicate string '%s'", value); |
3887 | + return -1; |
3888 | + } |
3889 | + |
3890 | + return 0; |
3891 | +} |
3892 | + |
3893 | +static int config_pivotdir(const char *key, char *value, struct lxc_conf *lxc_conf) |
3894 | +{ |
3895 | + if (strlen(value) >= MAXPATHLEN) { |
3896 | + ERROR("%s path is too long", value); |
3897 | + return -1; |
3898 | + } |
3899 | + |
3900 | + lxc_conf->rootfs.pivot = strdup(value); |
3901 | + if (!lxc_conf->rootfs.pivot) { |
3902 | + SYSERROR("failed to duplicate string %s", value); |
3903 | + return -1; |
3904 | + } |
3905 | + |
3906 | + return 0; |
3907 | +} |
3908 | + |
3909 | +static int config_utsname(const char *key, char *value, struct lxc_conf *lxc_conf) |
3910 | +{ |
3911 | + struct utsname *utsname; |
3912 | + |
3913 | + utsname = malloc(sizeof(*utsname)); |
3914 | + if (!utsname) { |
3915 | + SYSERROR("failed to allocate memory"); |
3916 | + return -1; |
3917 | + } |
3918 | + |
3919 | + if (strlen(value) >= sizeof(utsname->nodename)) { |
3920 | + ERROR("node name '%s' is too long", |
3921 | + utsname->nodename); |
3922 | + return -1; |
3923 | + } |
3924 | + |
3925 | + strcpy(utsname->nodename, value); |
3926 | + lxc_conf->utsname = utsname; |
3927 | + |
3928 | + return 0; |
3929 | +} |
3930 | + |
3931 | +static int parse_line(char *buffer, void *data) |
3932 | +{ |
3933 | + struct lxc_config_t *config; |
3934 | + char *line, *linep; |
3935 | + char *dot; |
3936 | + char *key; |
3937 | + char *value; |
3938 | + int ret = 0; |
3939 | + |
3940 | + if (lxc_is_line_empty(buffer)) |
3941 | + return 0; |
3942 | + |
3943 | + /* we have to dup the buffer otherwise, at the re-exec for |
3944 | + * reboot we modified the original string on the stack by |
3945 | + * replacing '=' by '\0' below |
3946 | + */ |
3947 | + linep = line = strdup(buffer); |
3948 | + if (!line) { |
3949 | + SYSERROR("failed to allocate memory for '%s'", buffer); |
3950 | + return -1; |
3951 | + } |
3952 | + |
3953 | + line += lxc_char_left_gc(line, strlen(line)); |
3954 | + |
3955 | + /* martian option - ignoring it, the commented lines beginning by '#' |
3956 | + * fall in this case |
3957 | + */ |
3958 | + if (strncmp(line, "lxc.", 4)) |
3959 | + goto out; |
3960 | + |
3961 | + ret = -1; |
3962 | + |
3963 | + dot = strstr(line, "="); |
3964 | + if (!dot) { |
3965 | + ERROR("invalid configuration line: %s", line); |
3966 | + goto out; |
3967 | + } |
3968 | + |
3969 | + *dot = '\0'; |
3970 | + value = dot + 1; |
3971 | + |
3972 | + key = line; |
3973 | + key[lxc_char_right_gc(key, strlen(key))] = '\0'; |
3974 | + |
3975 | + value += lxc_char_left_gc(value, strlen(value)); |
3976 | + value[lxc_char_right_gc(value, strlen(value))] = '\0'; |
3977 | + |
3978 | + config = lxc_getconfig(key); |
3979 | + if (!config) { |
3980 | + ERROR("unknown key %s", key); |
3981 | + goto out; |
3982 | + } |
3983 | + |
3984 | + ret = config->cb(key, value, data); |
3985 | + |
3986 | +out: |
3987 | + free(linep); |
3988 | + return ret; |
3989 | +} |
3990 | + |
3991 | +int lxc_config_readline(char *buffer, struct lxc_conf *conf) |
3992 | +{ |
3993 | + return parse_line(buffer, conf); |
3994 | +} |
3995 | + |
3996 | +int lxc_config_read(const char *file, struct lxc_conf *conf) |
3997 | +{ |
3998 | + return lxc_file_for_each_line(file, parse_line, conf); |
3999 | +} |
4000 | + |
4001 | +int lxc_config_define_add(struct lxc_list *defines, char* arg) |
4002 | +{ |
4003 | + struct lxc_list *dent; |
4004 | + |
4005 | + dent = malloc(sizeof(struct lxc_list)); |
4006 | + if (!dent) |
4007 | + return -1; |
4008 | + |
4009 | + dent->elem = arg; |
4010 | + lxc_list_add_tail(defines, dent); |
4011 | + return 0; |
4012 | +} |
4013 | + |
4014 | +int lxc_config_define_load(struct lxc_list *defines, struct lxc_conf *conf) |
4015 | +{ |
4016 | + struct lxc_list *it; |
4017 | + int ret = 0; |
4018 | + |
4019 | + lxc_list_for_each(it, defines) { |
4020 | + ret = lxc_config_readline(it->elem, conf); |
4021 | + if (ret) |
4022 | + break; |
4023 | + } |
4024 | + |
4025 | + lxc_list_for_each(it, defines) { |
4026 | + lxc_list_del(it); |
4027 | + free(it); |
4028 | + } |
4029 | + |
4030 | + return ret; |
4031 | +} |
4032 | + |
4033 | +signed long lxc_config_parse_arch(const char *arch) |
4034 | +{ |
4035 | + struct per_name { |
4036 | + char *name; |
4037 | + unsigned long per; |
4038 | + } pername[4] = { |
4039 | + { "x86", PER_LINUX32 }, |
4040 | + { "i686", PER_LINUX32 }, |
4041 | + { "x86_64", PER_LINUX }, |
4042 | + { "amd64", PER_LINUX }, |
4043 | + }; |
4044 | + size_t len = sizeof(pername) / sizeof(pername[0]); |
4045 | + |
4046 | + int i; |
4047 | + |
4048 | + for (i = 0; i < len; i++) { |
4049 | + if (!strcmp(pername[i].name, arch)) |
4050 | + return pername[i].per; |
4051 | + } |
4052 | + |
4053 | + return -1; |
4054 | +} |
4055 | + |
4056 | +static int lxc_get_conf_int(struct lxc_conf *c, char *retv, int inlen, int v) |
4057 | +{ |
4058 | + if (!retv) |
4059 | + inlen = 0; |
4060 | + else |
4061 | + memset(retv, 0, inlen); |
4062 | + return snprintf(retv, inlen, "%d", v); |
4063 | +} |
4064 | + |
4065 | +static int lxc_get_arch_entry(struct lxc_conf *c, char *retv, int inlen) |
4066 | +{ |
4067 | + int len, fulllen = 0; |
4068 | + |
4069 | + if (!retv) |
4070 | + inlen = 0; |
4071 | + else |
4072 | + memset(retv, 0, inlen); |
4073 | + |
4074 | + switch(c->personality) { |
4075 | + case PER_LINUX32: strprint(retv, inlen, "x86"); break; |
4076 | + case PER_LINUX: strprint(retv, inlen, "x86_64"); break; |
4077 | + default: break; |
4078 | + } |
4079 | + |
4080 | + return fulllen; |
4081 | +} |
4082 | + |
4083 | +/* |
4084 | + * If you ask for a specific cgroup value, i.e. lxc.cgroup.devices.list, |
4085 | + * then just the value(s) will be printed. Since there still could be |
4086 | + * more than one, it is newline-separated. |
4087 | + * (Maybe that's ambigous, since some values, i.e. devices.list, will |
4088 | + * already have newlines?) |
4089 | + * If you ask for 'lxc.cgroup", then all cgroup entries will be printed, |
4090 | + * in 'lxc.cgroup.subsystem.key = value' format. |
4091 | + */ |
4092 | +static int lxc_get_cgroup_entry(struct lxc_conf *c, char *retv, int inlen, char *key) |
4093 | +{ |
4094 | + int fulllen = 0, len; |
4095 | + int all = 0; |
4096 | + struct lxc_list *it; |
4097 | + |
4098 | + if (!retv) |
4099 | + inlen = 0; |
4100 | + else |
4101 | + memset(retv, 0, inlen); |
4102 | + |
4103 | + if (strcmp(key, "all") == 0) |
4104 | + all = 1; |
4105 | + |
4106 | + lxc_list_for_each(it, &c->cgroup) { |
4107 | + struct lxc_cgroup *cg = it->elem; |
4108 | + if (all) { |
4109 | + strprint(retv, inlen, "lxc.cgroup.%s = %s\n", cg->subsystem, cg->value); |
4110 | + } else if (strcmp(cg->subsystem, key) == 0) { |
4111 | + strprint(retv, inlen, "%s\n", cg->value); |
4112 | + } |
4113 | + } |
4114 | + return fulllen; |
4115 | +} |
4116 | + |
4117 | +static int lxc_get_item_hooks(struct lxc_conf *c, char *retv, int inlen, char *key) |
4118 | +{ |
4119 | + char *subkey; |
4120 | + int len, fulllen = 0, found = -1; |
4121 | + struct lxc_list *it; |
4122 | + int i; |
4123 | + |
4124 | + /* "lxc.hook.mount" */ |
4125 | + subkey = index(key, '.'); |
4126 | + if (subkey) subkey = index(subkey+1, '.'); |
4127 | + if (!subkey) |
4128 | + return -1; |
4129 | + subkey++; |
4130 | + if (!*subkey) |
4131 | + return -1; |
4132 | + for (i=0; i<NUM_LXC_HOOKS; i++) { |
4133 | + if (strcmp(lxchook_names[i], subkey) == 0) { |
4134 | + found=i; |
4135 | + break; |
4136 | + } |
4137 | + } |
4138 | + if (found == -1) |
4139 | + return -1; |
4140 | + |
4141 | + if (!retv) |
4142 | + inlen = 0; |
4143 | + else |
4144 | + memset(retv, 0, inlen); |
4145 | + |
4146 | + lxc_list_for_each(it, &c->hooks[found]) { |
4147 | + strprint(retv, inlen, "%s\n", (char *)it->elem); |
4148 | + } |
4149 | + return fulllen; |
4150 | +} |
4151 | + |
4152 | +static int lxc_get_item_cap_drop(struct lxc_conf *c, char *retv, int inlen) |
4153 | +{ |
4154 | + int len, fulllen = 0; |
4155 | + struct lxc_list *it; |
4156 | + |
4157 | + if (!retv) |
4158 | + inlen = 0; |
4159 | + else |
4160 | + memset(retv, 0, inlen); |
4161 | + |
4162 | + lxc_list_for_each(it, &c->caps) { |
4163 | + strprint(retv, inlen, "%s\n", (char *)it->elem); |
4164 | + } |
4165 | + return fulllen; |
4166 | +} |
4167 | + |
4168 | +static int lxc_get_mount_entries(struct lxc_conf *c, char *retv, int inlen) |
4169 | +{ |
4170 | + int len, fulllen = 0; |
4171 | + struct lxc_list *it; |
4172 | + |
4173 | + if (!retv) |
4174 | + inlen = 0; |
4175 | + else |
4176 | + memset(retv, 0, inlen); |
4177 | + |
4178 | + lxc_list_for_each(it, &c->mount_list) { |
4179 | + strprint(retv, inlen, "%s\n", (char *)it->elem); |
4180 | + } |
4181 | + return fulllen; |
4182 | +} |
4183 | + |
4184 | +/* |
4185 | + * lxc.network.0.XXX, where XXX can be: name, type, link, flags, type, |
4186 | + * macvlan.mode, veth.pair, vlan, ipv4, ipv6, upscript, hwaddr, mtu, |
4187 | + * ipv4_gateway, ipv6_gateway. ipvX_gateway can return 'auto' instead |
4188 | + * of an address. ipv4 and ipv6 return lists (newline-separated). |
4189 | + * things like veth.pair return '' if invalid (i.e. if called for vlan |
4190 | + * type). |
4191 | + */ |
4192 | +static int lxc_get_item_nic(struct lxc_conf *c, char *retv, int inlen, char *key) |
4193 | +{ |
4194 | + char *p1; |
4195 | + int len, fulllen = 0; |
4196 | + struct lxc_netdev *netdev; |
4197 | + |
4198 | + if (!retv) |
4199 | + inlen = 0; |
4200 | + else |
4201 | + memset(retv, 0, inlen); |
4202 | + |
4203 | + p1 = index(key, '.'); |
4204 | + if (!p1 || *(p1+1) == '\0') return -1; |
4205 | + p1++; |
4206 | + |
4207 | + netdev = get_netdev_from_key(key, &c->network); |
4208 | + if (!netdev) |
4209 | + return -1; |
4210 | + if (strcmp(p1, "name") == 0) { |
4211 | + if (netdev->name) |
4212 | + strprint(retv, inlen, "%s", netdev->name); |
4213 | + } else if (strcmp(p1, "type") == 0) { |
4214 | + strprint(retv, inlen, "%s", lxc_net_type_to_str(netdev->type)); |
4215 | + } else if (strcmp(p1, "link") == 0) { |
4216 | + if (netdev->link) |
4217 | + strprint(retv, inlen, "%s", netdev->link); |
4218 | + } else if (strcmp(p1, "flags") == 0) { |
4219 | + if (netdev->flags & IFF_UP) |
4220 | + strprint(retv, inlen, "up"); |
4221 | + } else if (strcmp(p1, "upscript") == 0) { |
4222 | + if (netdev->upscript) |
4223 | + strprint(retv, inlen, "%s", netdev->upscript); |
4224 | + } else if (strcmp(p1, "hwaddr") == 0) { |
4225 | + if (netdev->hwaddr) |
4226 | + strprint(retv, inlen, "%s", netdev->hwaddr); |
4227 | + } else if (strcmp(p1, "mtu") == 0) { |
4228 | + if (netdev->mtu) |
4229 | + strprint(retv, inlen, "%s", netdev->mtu); |
4230 | + } else if (strcmp(p1, "macvlan.mode") == 0) { |
4231 | + if (netdev->type == LXC_NET_MACVLAN) { |
4232 | + const char *mode; |
4233 | + switch (netdev->priv.macvlan_attr.mode) { |
4234 | + case MACVLAN_MODE_PRIVATE: mode = "private"; break; |
4235 | + case MACVLAN_MODE_VEPA: mode = "vepa"; break; |
4236 | + case MACVLAN_MODE_BRIDGE: mode = "bridge"; break; |
4237 | + default: mode = "(invalid)"; break; |
4238 | + } |
4239 | + strprint(retv, inlen, "%s", mode); |
4240 | + } |
4241 | + } else if (strcmp(p1, "veth.pair") == 0) { |
4242 | + if (netdev->type == LXC_NET_VETH && netdev->priv.veth_attr.pair) |
4243 | + strprint(retv, inlen, "%s", netdev->priv.veth_attr.pair); |
4244 | + } else if (strcmp(p1, "vlan") == 0) { |
4245 | + if (netdev->type == LXC_NET_VLAN) { |
4246 | + strprint(retv, inlen, "%d", netdev->priv.vlan_attr.vid); |
4247 | + } |
4248 | + } else if (strcmp(p1, "ipv4_gateway") == 0) { |
4249 | + if (netdev->ipv4_gateway_auto) { |
4250 | + strprint(retv, inlen, "auto"); |
4251 | + } else if (netdev->ipv4_gateway) { |
4252 | + char buf[INET_ADDRSTRLEN]; |
4253 | + inet_ntop(AF_INET, netdev->ipv4_gateway, buf, sizeof(buf)); |
4254 | + strprint(retv, inlen, "%s", buf); |
4255 | + } |
4256 | + } else if (strcmp(p1, "ipv4") == 0) { |
4257 | + struct lxc_list *it2; |
4258 | + lxc_list_for_each(it2, &netdev->ipv4) { |
4259 | + struct lxc_inetdev *i = it2->elem; |
4260 | + char buf[INET_ADDRSTRLEN]; |
4261 | + inet_ntop(AF_INET, &i->addr, buf, sizeof(buf)); |
4262 | + strprint(retv, inlen, "%s\n", buf); |
4263 | + } |
4264 | + } else if (strcmp(p1, "ipv6_gateway") == 0) { |
4265 | + if (netdev->ipv6_gateway_auto) { |
4266 | + strprint(retv, inlen, "auto"); |
4267 | + } else if (netdev->ipv6_gateway) { |
4268 | + char buf[INET_ADDRSTRLEN]; |
4269 | + inet_ntop(AF_INET, netdev->ipv6_gateway, buf, sizeof(buf)); |
4270 | + strprint(retv, inlen, "%s", buf); |
4271 | + } |
4272 | + } else if (strcmp(p1, "ipv6") == 0) { |
4273 | + struct lxc_list *it2; |
4274 | + lxc_list_for_each(it2, &netdev->ipv6) { |
4275 | + struct lxc_inetdev *i = it2->elem; |
4276 | + char buf[INET_ADDRSTRLEN]; |
4277 | + inet_ntop(AF_INET6, &i->addr, buf, sizeof(buf)); |
4278 | + strprint(retv, inlen, "%s\n", buf); |
4279 | + } |
4280 | + } |
4281 | + return fulllen; |
4282 | +} |
4283 | + |
4284 | +static int lxc_get_item_network(struct lxc_conf *c, char *retv, int inlen) |
4285 | +{ |
4286 | + int len, fulllen = 0; |
4287 | + struct lxc_list *it; |
4288 | + |
4289 | + if (!retv) |
4290 | + inlen = 0; |
4291 | + else |
4292 | + memset(retv, 0, inlen); |
4293 | + |
4294 | + lxc_list_for_each(it, &c->network) { |
4295 | + struct lxc_netdev *n = it->elem; |
4296 | + const char *t = lxc_net_type_to_str(n->type); |
4297 | + strprint(retv, inlen, "%s\n", t ? t : "(invalid)"); |
4298 | + } |
4299 | + return fulllen; |
4300 | +} |
4301 | + |
4302 | +int lxc_get_config_item(struct lxc_conf *c, char *key, char *retv, int inlen) |
4303 | +{ |
4304 | + char *v = NULL; |
4305 | + |
4306 | + if (strcmp(key, "lxc.mount.entry") == 0) |
4307 | + return lxc_get_mount_entries(c, retv, inlen); |
4308 | + else if (strcmp(key, "lxc.mount") == 0) |
4309 | + v = c->fstab; |
4310 | + else if (strcmp(key, "lxc.tty") == 0) |
4311 | + return lxc_get_conf_int(c, retv, inlen, c->tty); |
4312 | + else if (strcmp(key, "lxc.pts") == 0) |
4313 | + return lxc_get_conf_int(c, retv, inlen, c->pts); |
4314 | + else if (strcmp(key, "lxc.devttydir") == 0) |
4315 | + v = c->ttydir; |
4316 | + else if (strcmp(key, "lxc.arch") == 0) |
4317 | + return lxc_get_arch_entry(c, retv, inlen); |
4318 | + else if (strcmp(key, "lxc.aa_profile") == 0) |
4319 | + v = c->aa_profile; |
4320 | + else if (strcmp(key, "lxc.cgroup") == 0) // all cgroup info |
4321 | + return lxc_get_cgroup_entry(c, retv, inlen, "all"); |
4322 | + else if (strncmp(key, "lxc.cgroup.", 11) == 0) // specific cgroup info |
4323 | + return lxc_get_cgroup_entry(c, retv, inlen, key + 11); |
4324 | + else if (strcmp(key, "lxc.utsname") == 0) |
4325 | + v = c->utsname ? c->utsname->nodename : NULL; |
4326 | + else if (strcmp(key, "lxc.console") == 0) |
4327 | + v = c->console.path; |
4328 | + else if (strcmp(key, "lxc.rootfs.mount") == 0) |
4329 | + v = c->rootfs.mount; |
4330 | + else if (strcmp(key, "lxc.rootfs") == 0) |
4331 | + v = c->rootfs.path; |
4332 | + else if (strcmp(key, "lxc.pivotdir") == 0) |
4333 | + v = c->rootfs.pivot; |
4334 | + else if (strcmp(key, "lxc.cap.drop") == 0) |
4335 | + return lxc_get_item_cap_drop(c, retv, inlen); |
4336 | + else if (strncmp(key, "lxc.hook", 8) == 0) |
4337 | + return lxc_get_item_hooks(c, retv, inlen, key); |
4338 | + else if (strcmp(key, "lxc.network") == 0) |
4339 | + return lxc_get_item_network(c, retv, inlen); |
4340 | + else if (strncmp(key, "lxc.network.", 12) == 0) |
4341 | + return lxc_get_item_nic(c, retv, inlen, key + 12); |
4342 | + else return -1; |
4343 | + |
4344 | + if (!v) |
4345 | + return 0; |
4346 | + if (retv && inlen >= strlen(v) + 1) |
4347 | + strncpy(retv, v, strlen(v)+1); |
4348 | + return strlen(v); |
4349 | +} |
4350 | + |
4351 | +int lxc_clear_config_item(struct lxc_conf *c, char *key) |
4352 | +{ |
4353 | + if (strcmp(key, "lxc.network") == 0) |
4354 | + return lxc_clear_config_network(c); |
4355 | + else if (strncmp(key, "lxc.network.", 12) == 0) |
4356 | + return lxc_clear_nic(c, key + 12); |
4357 | + else if (strcmp(key, "lxc.cap.drop") == 0) |
4358 | + return lxc_clear_config_caps(c); |
4359 | + else if (strncmp(key, "lxc.cgroup", 10) == 0) |
4360 | + return lxc_clear_cgroups(c, key); |
4361 | + else if (strcmp(key, "lxc.mount.entries") == 0) |
4362 | + return lxc_clear_mount_entries(c); |
4363 | + else if (strcmp(key, "lxc.hook") == 0) |
4364 | + return lxc_clear_hooks(c); |
4365 | + |
4366 | + return -1; |
4367 | +} |
4368 | + |
4369 | +/* |
4370 | + * writing out a confile. |
4371 | + */ |
4372 | +void write_config(FILE *fout, struct lxc_conf *c) |
4373 | +{ |
4374 | + struct lxc_list *it; |
4375 | + int i; |
4376 | + |
4377 | + if (c->fstab) |
4378 | + fprintf(fout, "lxc.mount = %s\n", c->fstab); |
4379 | + lxc_list_for_each(it, &c->mount_list) { |
4380 | + fprintf(fout, "lxc.mount.entry = %s\n", (char *)it->elem); |
4381 | + } |
4382 | + if (c->tty) |
4383 | + fprintf(fout, "lxc.tty = %d\n", c->tty); |
4384 | + if (c->pts) |
4385 | + fprintf(fout, "lxc.pts = %d\n", c->pts); |
4386 | + if (c->ttydir) |
4387 | + fprintf(fout, "lxc.devttydir = %s\n", c->ttydir); |
4388 | + switch(c->personality) { |
4389 | + case PER_LINUX32: fprintf(fout, "lxc.arch = x86\n"); break; |
4390 | + case PER_LINUX: fprintf(fout, "lxc.arch = x86_64\n"); break; |
4391 | + default: break; |
4392 | + } |
4393 | + if (c->aa_profile) |
4394 | + fprintf(fout, "lxc.aa_profile = %s\n", c->aa_profile); |
4395 | + lxc_list_for_each(it, &c->cgroup) { |
4396 | + struct lxc_cgroup *cg = it->elem; |
4397 | + fprintf(fout, "lxc.cgroup.%s = %s\n", cg->subsystem, cg->value); |
4398 | + } |
4399 | + if (c->utsname) |
4400 | + fprintf(fout, "lxc.utsname = %s\n", c->utsname->nodename); |
4401 | + lxc_list_for_each(it, &c->network) { |
4402 | + struct lxc_netdev *n = it->elem; |
4403 | + const char *t = lxc_net_type_to_str(n->type); |
4404 | + struct lxc_list *it2; |
4405 | + fprintf(fout, "lxc.network.type = %s\n", t ? t : "(invalid)"); |
4406 | + if (n->flags & IFF_UP) |
4407 | + fprintf(fout, "lxc.network.flags = up\n"); |
4408 | + if (n->link) |
4409 | + fprintf(fout, "lxc.network.link = %s\n", n->link); |
4410 | + if (n->name) |
4411 | + fprintf(fout, "lxc.network.name = %s\n", n->name); |
4412 | + if (n->type == LXC_NET_MACVLAN) { |
4413 | + const char *mode; |
4414 | + switch (n->priv.macvlan_attr.mode) { |
4415 | + case MACVLAN_MODE_PRIVATE: mode = "private"; break; |
4416 | + case MACVLAN_MODE_VEPA: mode = "vepa"; break; |
4417 | + case MACVLAN_MODE_BRIDGE: mode = "bridge"; break; |
4418 | + default: mode = "(invalid)"; break; |
4419 | + } |
4420 | + fprintf(fout, "lxc.network.macvlan.mode = %s\n", mode); |
4421 | + } else if (n->type == LXC_NET_VETH) { |
4422 | + if (n->priv.veth_attr.pair) |
4423 | + fprintf(fout, "lxc.network.veth.pair = %s\n", |
4424 | + n->priv.veth_attr.pair); |
4425 | + } else if (n->type == LXC_NET_VLAN) { |
4426 | + fprintf(fout, "lxc.network.vlan.id = %d\n", n->priv.vlan_attr.vid); |
4427 | + } |
4428 | + if (n->upscript) |
4429 | + fprintf(fout, "lxc.network.script.up = %s\n", n->upscript); |
4430 | + if (n->hwaddr) |
4431 | + fprintf(fout, "lxc.network.hwaddr = %s\n", n->hwaddr); |
4432 | + if (n->mtu) |
4433 | + fprintf(fout, "lxc.network.mtu = %s\n", n->mtu); |
4434 | + if (n->ipv4_gateway_auto) |
4435 | + fprintf(fout, "lxc.network.ipv4.gateway = auto\n"); |
4436 | + else if (n->ipv4_gateway) { |
4437 | + char buf[INET_ADDRSTRLEN]; |
4438 | + inet_ntop(AF_INET, n->ipv4_gateway, buf, sizeof(buf)); |
4439 | + fprintf(fout, "lxc.network.ipv4.gateway = %s\n", buf); |
4440 | + } |
4441 | + lxc_list_for_each(it2, &n->ipv4) { |
4442 | + struct lxc_inetdev *i = it2->elem; |
4443 | + char buf[INET_ADDRSTRLEN]; |
4444 | + inet_ntop(AF_INET, &i->addr, buf, sizeof(buf)); |
4445 | + fprintf(fout, "lxc.network.ipv4 = %s\n", buf); |
4446 | + } |
4447 | + if (n->ipv6_gateway_auto) |
4448 | + fprintf(fout, "lxc.network.ipv6.gateway = auto\n"); |
4449 | + else if (n->ipv6_gateway) { |
4450 | + char buf[INET6_ADDRSTRLEN]; |
4451 | + inet_ntop(AF_INET6, n->ipv6_gateway, buf, sizeof(buf)); |
4452 | + fprintf(fout, "lxc.network.ipv6.gateway = %s\n", buf); |
4453 | + } |
4454 | + lxc_list_for_each(it2, &n->ipv6) { |
4455 | + struct lxc_inet6dev *i = it2->elem; |
4456 | + char buf[INET6_ADDRSTRLEN]; |
4457 | + inet_ntop(AF_INET, &i->addr, buf, sizeof(buf)); |
4458 | + fprintf(fout, "lxc.network.ipv6 = %s\n", buf); |
4459 | + } |
4460 | + } |
4461 | + lxc_list_for_each(it, &c->caps) |
4462 | + fprintf(fout, "lxc.cap.drop = %s\n", (char *)it->elem); |
4463 | + for (i=0; i<NUM_LXC_HOOKS; i++) { |
4464 | + lxc_list_for_each(it, &c->hooks[i]) |
4465 | + fprintf(fout, "lxc.hook.%s = %s\n", |
4466 | + lxchook_names[i], (char *)it->elem); |
4467 | + } |
4468 | + if (c->console.path) |
4469 | + fprintf(fout, "lxc.console = %s\n", c->console.path); |
4470 | + if (c->rootfs.path) |
4471 | + fprintf(fout, "lxc.rootfs = %s\n", c->rootfs.path); |
4472 | + if (c->rootfs.mount && strcmp(c->rootfs.mount, LXCROOTFSMOUNT) != 0) |
4473 | + fprintf(fout, "lxc.rootfs.mount = %s\n", c->rootfs.mount); |
4474 | + if (c->rootfs.pivot) |
4475 | + fprintf(fout, "lxc.pivotdir = %s\n", c->rootfs.pivot); |
4476 | +} |
4477 | |
4478 | === added directory '.pc/0221-make-nonflush-upgrades-robust' |
4479 | === renamed directory '.pc/0221-make-nonflush-upgrades-robust' => '.pc/0221-make-nonflush-upgrades-robust.moved' |
4480 | === added file '.pc/0221-make-nonflush-upgrades-robust/.timestamp' |
4481 | === added directory '.pc/0221-make-nonflush-upgrades-robust/templates' |
4482 | === added file '.pc/0221-make-nonflush-upgrades-robust/templates/lxc-ubuntu.in' |
4483 | --- .pc/0221-make-nonflush-upgrades-robust/templates/lxc-ubuntu.in 1970-01-01 00:00:00 +0000 |
4484 | +++ .pc/0221-make-nonflush-upgrades-robust/templates/lxc-ubuntu.in 2012-09-14 20:24:18 +0000 |
4485 | @@ -0,0 +1,713 @@ |
4486 | +#!/bin/bash |
4487 | + |
4488 | +# |
4489 | +# template script for generating ubuntu container for LXC |
4490 | +# |
4491 | +# This script consolidates and extends the existing lxc ubuntu scripts |
4492 | +# |
4493 | + |
4494 | +# Copyright © 2011 Serge Hallyn <serge.hallyn@canonical.com> |
4495 | +# Copyright © 2010 Wilhelm Meier |
4496 | +# Author: Wilhelm Meier <wilhelm.meier@fh-kl.de> |
4497 | +# |
4498 | +# This program is free software; you can redistribute it and/or modify |
4499 | +# it under the terms of the GNU General Public License version 2, as |
4500 | +# published by the Free Software Foundation. |
4501 | + |
4502 | +# This program is distributed in the hope that it will be useful, |
4503 | +# but WITHOUT ANY WARRANTY; without even the implied warranty of |
4504 | +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
4505 | +# GNU General Public License for more details. |
4506 | + |
4507 | +# You should have received a copy of the GNU General Public License along |
4508 | +# with this program; if not, write to the Free Software Foundation, Inc., |
4509 | +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
4510 | +# |
4511 | + |
4512 | +set -e |
4513 | + |
4514 | +if [ -r /etc/default/lxc ]; then |
4515 | + . /etc/default/lxc |
4516 | +fi |
4517 | + |
4518 | +configure_ubuntu() |
4519 | +{ |
4520 | + rootfs=$1 |
4521 | + hostname=$2 |
4522 | + release=$3 |
4523 | + |
4524 | + # configure the network using the dhcp |
4525 | + cat <<EOF > $rootfs/etc/network/interfaces |
4526 | +# This file describes the network interfaces available on your system |
4527 | +# and how to activate them. For more information, see interfaces(5). |
4528 | + |
4529 | +# The loopback network interface |
4530 | +auto lo |
4531 | +iface lo inet loopback |
4532 | + |
4533 | +auto eth0 |
4534 | +iface eth0 inet dhcp |
4535 | +EOF |
4536 | + |
4537 | + # set the hostname |
4538 | + cat <<EOF > $rootfs/etc/hostname |
4539 | +$hostname |
4540 | +EOF |
4541 | + # set minimal hosts |
4542 | + cat <<EOF > $rootfs/etc/hosts |
4543 | +127.0.0.1 localhost |
4544 | +127.0.1.1 $hostname |
4545 | + |
4546 | +# The following lines are desirable for IPv6 capable hosts |
4547 | +::1 ip6-localhost ip6-loopback |
4548 | +fe00::0 ip6-localnet |
4549 | +ff00::0 ip6-mcastprefix |
4550 | +ff02::1 ip6-allnodes |
4551 | +ff02::2 ip6-allrouters |
4552 | +EOF |
4553 | + |
4554 | + if [ ! -f $rootfs/etc/init/container-detect.conf ]; then |
4555 | + # suppress log level output for udev |
4556 | + sed -i "s/=\"err\"/=0/" $rootfs/etc/udev/udev.conf |
4557 | + |
4558 | + # remove jobs for consoles 5 and 6 since we only create 4 consoles in |
4559 | + # this template |
4560 | + rm -f $rootfs/etc/init/tty{5,6}.conf |
4561 | + fi |
4562 | + |
4563 | + if [ -z "$bindhome" ]; then |
4564 | + chroot $rootfs useradd --create-home -s /bin/bash ubuntu |
4565 | + echo "ubuntu:ubuntu" | chroot $rootfs chpasswd |
4566 | + fi |
4567 | + |
4568 | + return 0 |
4569 | +} |
4570 | + |
4571 | +# finish setting up the user in the container by injecting ssh key and |
4572 | +# adding sudo group membership. |
4573 | +# passed-in user is either 'ubuntu' or the user to bind in from host. |
4574 | +finalize_user() |
4575 | +{ |
4576 | + user=$1 |
4577 | + |
4578 | + sudo_version=$(chroot $rootfs dpkg-query -W -f='${Version}' sudo) |
4579 | + |
4580 | + if chroot $rootfs dpkg --compare-versions $sudo_version gt "1.8.3p1-1"; then |
4581 | + groups="sudo" |
4582 | + else |
4583 | + groups="sudo admin" |
4584 | + fi |
4585 | + |
4586 | + for group in $groups; do |
4587 | + chroot $rootfs groupadd --system $group >/dev/null 2>&1 || true |
4588 | + chroot $rootfs adduser ${user} $group >/dev/null 2>&1 || true |
4589 | + done |
4590 | + |
4591 | + if [ -n "$auth_key" -a -f "$auth_key" ]; then |
4592 | + u_path="/home/${user}/.ssh" |
4593 | + root_u_path="$rootfs/$u_path" |
4594 | + |
4595 | + mkdir -p $root_u_path |
4596 | + cp $auth_key "$root_u_path/authorized_keys" |
4597 | + chroot $rootfs chown -R ${user}: "$u_path" |
4598 | + |
4599 | + echo "Inserted SSH public key from $auth_key into /home/${user}/.ssh/authorized_keys" |
4600 | + fi |
4601 | + return 0 |
4602 | +} |
4603 | + |
4604 | +write_sourceslist() |
4605 | +{ |
4606 | + # $1 => path to the rootfs |
4607 | + # $2 => architecture we want to add |
4608 | + # $3 => whether to use the multi-arch syntax or not |
4609 | + |
4610 | + case $2 in |
4611 | + amd64|i386) |
4612 | + MIRROR=${MIRROR:-http://archive.ubuntu.com/ubuntu} |
4613 | + SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.ubuntu.com/ubuntu} |
4614 | + ;; |
4615 | + *) |
4616 | + MIRROR=${MIRROR:-http://ports.ubuntu.com/ubuntu-ports} |
4617 | + SECURITY_MIRROR=${SECURITY_MIRROR:-http://ports.ubuntu.com/ubuntu-ports} |
4618 | + ;; |
4619 | + esac |
4620 | + if [ -n "$3" ]; then |
4621 | + cat >> "$1/etc/apt/sources.list" << EOF |
4622 | +deb [arch=$2] $MIRROR ${release} main restricted universe multiverse |
4623 | +deb [arch=$2] $MIRROR ${release}-updates main restricted universe multiverse |
4624 | +deb [arch=$2] $SECURITY_MIRROR ${release}-security main restricted universe multiverse |
4625 | +EOF |
4626 | + else |
4627 | + cat >> "$1/etc/apt/sources.list" << EOF |
4628 | +deb $MIRROR ${release} main restricted universe multiverse |
4629 | +deb $MIRROR ${release}-updates main restricted universe multiverse |
4630 | +deb $SECURITY_MIRROR ${release}-security main restricted universe multiverse |
4631 | +EOF |
4632 | + fi |
4633 | +} |
4634 | + |
4635 | +cleanup() |
4636 | +{ |
4637 | + rm -rf $cache/partial-$arch |
4638 | + rm -rf $cache/rootfs-$arch |
4639 | +} |
4640 | + |
4641 | +download_ubuntu() |
4642 | +{ |
4643 | + cache=$1 |
4644 | + arch=$2 |
4645 | + release=$3 |
4646 | + |
4647 | + packages=vim,ssh |
4648 | + echo "installing packages: $packages" |
4649 | + |
4650 | + trap cleanup EXIT SIGHUP SIGINT SIGTERM |
4651 | + # check the mini ubuntu was not already downloaded |
4652 | + mkdir -p "$cache/partial-$arch" |
4653 | + if [ $? -ne 0 ]; then |
4654 | + echo "Failed to create '$cache/partial-$arch' directory" |
4655 | + return 1 |
4656 | + fi |
4657 | + |
4658 | + # download a mini ubuntu into a cache |
4659 | + echo "Downloading ubuntu $release minimal ..." |
4660 | + if [ -n "$(which qemu-debootstrap)" ]; then |
4661 | + qemu-debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR |
4662 | + else |
4663 | + debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR |
4664 | + fi |
4665 | + |
4666 | + if [ $? -ne 0 ]; then |
4667 | + echo "Failed to download the rootfs, aborting." |
4668 | + return 1 |
4669 | + fi |
4670 | + |
4671 | + # Serge isn't sure whether we should avoid doing this when |
4672 | + # $release == `distro-info -d` |
4673 | + echo "Installing updates" |
4674 | + > $cache/partial-$arch/etc/apt/sources.list |
4675 | + write_sourceslist $cache/partial-$arch/ $arch |
4676 | + |
4677 | + chroot "$1/partial-${arch}" apt-get update |
4678 | + if [ $? -ne 0 ]; then |
4679 | + echo "Failed to update the apt cache" |
4680 | + return 1 |
4681 | + fi |
4682 | + cat > "$1/partial-${arch}"/usr/sbin/policy-rc.d << EOF |
4683 | +#!/bin/sh |
4684 | +exit 101 |
4685 | +EOF |
4686 | + chmod +x "$1/partial-${arch}"/usr/sbin/policy-rc.d |
4687 | + |
4688 | + lxc-unshare -s MOUNT -- chroot "$1/partial-${arch}" apt-get dist-upgrade -y |
4689 | + ret=$? |
4690 | + rm -f "$1/partial-${arch}"/usr/sbin/policy-rc.d |
4691 | + |
4692 | + if [ $ret -ne 0 ]; then |
4693 | + echo "Failed to upgrade the cache" |
4694 | + return 1 |
4695 | + fi |
4696 | + |
4697 | + chroot "$1/partial-${arch}" apt-get clean |
4698 | + |
4699 | + mv "$1/partial-$arch" "$1/rootfs-$arch" |
4700 | + trap EXIT |
4701 | + trap SIGINT |
4702 | + trap SIGTERM |
4703 | + trap SIGHUP |
4704 | + echo "Download complete" |
4705 | + return 0 |
4706 | +} |
4707 | + |
4708 | +copy_ubuntu() |
4709 | +{ |
4710 | + cache=$1 |
4711 | + arch=$2 |
4712 | + rootfs=$3 |
4713 | + |
4714 | + # make a local copy of the miniubuntu |
4715 | + echo "Copying rootfs to $rootfs ..." |
4716 | + mkdir -p $rootfs |
4717 | + rsync -a $cache/rootfs-$arch/ $rootfs/ || return 1 |
4718 | + return 0 |
4719 | +} |
4720 | + |
4721 | +install_ubuntu() |
4722 | +{ |
4723 | + rootfs=$1 |
4724 | + release=$2 |
4725 | + flushcache=$3 |
4726 | + cache="/var/cache/lxc/$release" |
4727 | + mkdir -p /var/lock/subsys/ |
4728 | + |
4729 | + ( |
4730 | + flock -x 200 |
4731 | + if [ $? -ne 0 ]; then |
4732 | + echo "Cache repository is busy." |
4733 | + return 1 |
4734 | + fi |
4735 | + |
4736 | + |
4737 | + if [ $flushcache -eq 1 ]; then |
4738 | + echo "Flushing cache..." |
4739 | + rm -rf "$cache/partial-$arch" |
4740 | + rm -rf "$cache/rootfs-$arch" |
4741 | + fi |
4742 | + |
4743 | + echo "Checking cache download in $cache/rootfs-$arch ... " |
4744 | + if [ ! -e "$cache/rootfs-$arch" ]; then |
4745 | + download_ubuntu $cache $arch $release |
4746 | + if [ $? -ne 0 ]; then |
4747 | + echo "Failed to download 'ubuntu $release base'" |
4748 | + return 1 |
4749 | + fi |
4750 | + fi |
4751 | + |
4752 | + echo "Copy $cache/rootfs-$arch to $rootfs ... " |
4753 | + copy_ubuntu $cache $arch $rootfs |
4754 | + if [ $? -ne 0 ]; then |
4755 | + echo "Failed to copy rootfs" |
4756 | + return 1 |
4757 | + fi |
4758 | + |
4759 | + return 0 |
4760 | + |
4761 | + ) 200>/var/lock/subsys/lxc |
4762 | + |
4763 | + return $? |
4764 | +} |
4765 | + |
4766 | +copy_configuration() |
4767 | +{ |
4768 | + path=$1 |
4769 | + rootfs=$2 |
4770 | + name=$3 |
4771 | + arch=$4 |
4772 | + release=$5 |
4773 | + |
4774 | + if [ $arch = "i386" ]; then |
4775 | + arch="i686" |
4776 | + fi |
4777 | + |
4778 | + ttydir="" |
4779 | + if [ -f $rootfs/etc/init/container-detect.conf ]; then |
4780 | + ttydir=" lxc" |
4781 | + fi |
4782 | + |
4783 | + # if there is exactly one veth network entry, make sure it has an |
4784 | + # associated hwaddr. |
4785 | + nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l` |
4786 | + if [ $nics -eq 1 ]; then |
4787 | + grep -q "^lxc.network.hwaddr" $path/config || cat <<EOF >> $path/config |
4788 | +lxc.network.hwaddr = 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//') |
4789 | +EOF |
4790 | + fi |
4791 | + |
4792 | + grep -q "^lxc.rootfs" $path/config 2>/dev/null || echo "lxc.rootfs = $rootfs" >> $path/config |
4793 | + cat <<EOF >> $path/config |
4794 | +lxc.utsname = $name |
4795 | + |
4796 | +lxc.devttydir =$ttydir |
4797 | +lxc.tty = 4 |
4798 | +lxc.pts = 1024 |
4799 | +lxc.mount = $path/fstab |
4800 | +lxc.arch = $arch |
4801 | +lxc.cap.drop = sys_module mac_admin mac_override |
4802 | +lxc.pivotdir = lxc_putold |
4803 | + |
4804 | +# uncomment the next line to run the container unconfined: |
4805 | +#lxc.aa_profile = unconfined |
4806 | + |
4807 | +lxc.cgroup.devices.deny = a |
4808 | +# Allow any mknod (but not using the node) |
4809 | +lxc.cgroup.devices.allow = c *:* m |
4810 | +lxc.cgroup.devices.allow = b *:* m |
4811 | +# /dev/null and zero |
4812 | +lxc.cgroup.devices.allow = c 1:3 rwm |
4813 | +lxc.cgroup.devices.allow = c 1:5 rwm |
4814 | +# consoles |
4815 | +lxc.cgroup.devices.allow = c 5:1 rwm |
4816 | +lxc.cgroup.devices.allow = c 5:0 rwm |
4817 | +#lxc.cgroup.devices.allow = c 4:0 rwm |
4818 | +#lxc.cgroup.devices.allow = c 4:1 rwm |
4819 | +# /dev/{,u}random |
4820 | +lxc.cgroup.devices.allow = c 1:9 rwm |
4821 | +lxc.cgroup.devices.allow = c 1:8 rwm |
4822 | +lxc.cgroup.devices.allow = c 136:* rwm |
4823 | +lxc.cgroup.devices.allow = c 5:2 rwm |
4824 | +# rtc |
4825 | +lxc.cgroup.devices.allow = c 254:0 rwm |
4826 | +#fuse |
4827 | +lxc.cgroup.devices.allow = c 10:229 rwm |
4828 | +#tun |
4829 | +lxc.cgroup.devices.allow = c 10:200 rwm |
4830 | +#full |
4831 | +lxc.cgroup.devices.allow = c 1:7 rwm |
4832 | +#hpet |
4833 | +lxc.cgroup.devices.allow = c 10:228 rwm |
4834 | +#kvm |
4835 | +lxc.cgroup.devices.allow = c 10:232 rwm |
4836 | +EOF |
4837 | + |
4838 | + cat <<EOF > $path/fstab |
4839 | +proc proc proc nodev,noexec,nosuid 0 0 |
4840 | +sysfs sys sysfs defaults 0 0 |
4841 | +EOF |
4842 | + |
4843 | + if [ $? -ne 0 ]; then |
4844 | + echo "Failed to add configuration" |
4845 | + return 1 |
4846 | + fi |
4847 | + |
4848 | + return 0 |
4849 | +} |
4850 | + |
4851 | +trim() |
4852 | +{ |
4853 | + rootfs=$1 |
4854 | + release=$2 |
4855 | + |
4856 | + # provide the lxc service |
4857 | + cat <<EOF > $rootfs/etc/init/lxc.conf |
4858 | +# fake some events needed for correct startup other services |
4859 | + |
4860 | +description "Container Upstart" |
4861 | + |
4862 | +start on startup |
4863 | + |
4864 | +script |
4865 | + rm -rf /var/run/*.pid |
4866 | + rm -rf /var/run/network/* |
4867 | + /sbin/initctl emit stopped JOB=udevtrigger --no-wait |
4868 | + /sbin/initctl emit started JOB=udev --no-wait |
4869 | +end script |
4870 | +EOF |
4871 | + |
4872 | + # fix buggus runlevel with sshd |
4873 | + cat <<EOF > $rootfs/etc/init/ssh.conf |
4874 | +# ssh - OpenBSD Secure Shell server |
4875 | +# |
4876 | +# The OpenSSH server provides secure shell access to the system. |
4877 | + |
4878 | +description "OpenSSH server" |
4879 | + |
4880 | +start on filesystem |
4881 | +stop on runlevel [!2345] |
4882 | + |
4883 | +expect fork |
4884 | +respawn |
4885 | +respawn limit 10 5 |
4886 | +umask 022 |
4887 | +# replaces SSHD_OOM_ADJUST in /etc/default/ssh |
4888 | +oom never |
4889 | + |
4890 | +pre-start script |
4891 | + test -x /usr/sbin/sshd || { stop; exit 0; } |
4892 | + test -e /etc/ssh/sshd_not_to_be_run && { stop; exit 0; } |
4893 | + test -c /dev/null || { stop; exit 0; } |
4894 | + |
4895 | + mkdir -p -m0755 /var/run/sshd |
4896 | +end script |
4897 | + |
4898 | +# if you used to set SSHD_OPTS in /etc/default/ssh, you can change the |
4899 | +# 'exec' line here instead |
4900 | +exec /usr/sbin/sshd |
4901 | +EOF |
4902 | + |
4903 | + cat <<EOF > $rootfs/etc/init/console.conf |
4904 | +# console - getty |
4905 | +# |
4906 | +# This service maintains a console on tty1 from the point the system is |
4907 | +# started until it is shut down again. |
4908 | + |
4909 | +start on stopped rc RUNLEVEL=[2345] |
4910 | +stop on runlevel [!2345] |
4911 | + |
4912 | +respawn |
4913 | +exec /sbin/getty -8 38400 /dev/console |
4914 | +EOF |
4915 | + |
4916 | + cat <<EOF > $rootfs/lib/init/fstab |
4917 | +# /lib/init/fstab: cleared out for bare-bones lxc |
4918 | +EOF |
4919 | + |
4920 | + # reconfigure some services |
4921 | + if [ -z "$LANG" ]; then |
4922 | + chroot $rootfs locale-gen en_US.UTF-8 |
4923 | + chroot $rootfs update-locale LANG=en_US.UTF-8 |
4924 | + else |
4925 | + chroot $rootfs locale-gen $LANG |
4926 | + chroot $rootfs update-locale LANG=$LANG |
4927 | + fi |
4928 | + |
4929 | + # remove pointless services in a container |
4930 | + chroot $rootfs /usr/sbin/update-rc.d -f ondemand remove |
4931 | + |
4932 | + chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls u*.conf); do mv $f $f.orig; done' |
4933 | + chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls tty[2-9].conf); do mv $f $f.orig; done' |
4934 | + chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls plymouth*.conf); do mv $f $f.orig; done' |
4935 | + chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls hwclock*.conf); do mv $f $f.orig; done' |
4936 | + chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls module*.conf); do mv $f $f.orig; done' |
4937 | + |
4938 | + # if this isn't lucid, then we need to twiddle the network upstart bits :( |
4939 | + if [ $release != "lucid" ]; then |
4940 | + sed -i 's/^.*emission handled.*$/echo Emitting lo/' $rootfs/etc/network/if-up.d/upstart |
4941 | + fi |
4942 | +} |
4943 | + |
4944 | +post_process() |
4945 | +{ |
4946 | + rootfs=$1 |
4947 | + release=$2 |
4948 | + trim_container=$3 |
4949 | + |
4950 | + if [ $trim_container -eq 1 ]; then |
4951 | + trim $rootfs $release |
4952 | + elif [ ! -f $rootfs/etc/init/container-detect.conf ]; then |
4953 | + # Make sure we have a working resolv.conf |
4954 | + cresolvonf="${rootfs}/etc/resolv.conf" |
4955 | + mv $cresolvonf ${cresolvonf}.lxcbak |
4956 | + cat /etc/resolv.conf > ${cresolvonf} |
4957 | + |
4958 | + # for lucid, if not trimming, then add the ubuntu-virt |
4959 | + # ppa and install lxcguest |
4960 | + if [ $release = "lucid" ]; then |
4961 | + chroot $rootfs apt-get install --force-yes -y python-software-properties |
4962 | + chroot $rootfs add-apt-repository ppa:ubuntu-virt/ppa |
4963 | + fi |
4964 | + |
4965 | + chroot $rootfs apt-get update |
4966 | + chroot $rootfs apt-get install --force-yes -y lxcguest |
4967 | + |
4968 | + # Restore old resolv.conf |
4969 | + rm -f ${cresolvonf} |
4970 | + mv ${cresolvonf}.lxcbak ${cresolvonf} |
4971 | + fi |
4972 | + |
4973 | + # If the container isn't running a native architecture, setup multiarch |
4974 | + if [ -x "$(ls -1 ${rootfs}/usr/bin/qemu-*-static 2>/dev/null)" ]; then |
4975 | + dpkg_version=$(chroot $rootfs dpkg-query -W -f='${Version}' dpkg) |
4976 | + if chroot $rootfs dpkg --compare-versions $dpkg_version ge "1.16.2"; then |
4977 | + chroot $rootfs dpkg --add-architecture ${hostarch} |
4978 | + else |
4979 | + mkdir -p ${rootfs}/etc/dpkg/dpkg.cfg.d |
4980 | + echo "foreign-architecture ${hostarch}" > ${rootfs}/etc/dpkg/dpkg.cfg.d/lxc-multiarch |
4981 | + fi |
4982 | + |
4983 | + # Save existing value of MIRROR and SECURITY_MIRROR |
4984 | + DEFAULT_MIRROR=$MIRROR |
4985 | + DEFAULT_SECURITY_MIRROR=$SECURITY_MIRROR |
4986 | + |
4987 | + # Write a new sources.list containing both native and multiarch entries |
4988 | + > ${rootfs}/etc/apt/sources.list |
4989 | + write_sourceslist $rootfs $arch "native" |
4990 | + |
4991 | + MIRROR=$DEFAULT_MIRROR |
4992 | + SECURITY_MIRROR=$DEFAULT_SECURITY_MIRROR |
4993 | + write_sourceslist $rootfs $hostarch "multiarch" |
4994 | + |
4995 | + # Finally update the lists and install upstart using the host architecture |
4996 | + chroot $rootfs apt-get update |
4997 | + chroot $rootfs apt-get install --force-yes -y --no-install-recommends upstart:${hostarch} mountall:${hostarch} iproute:${hostarch} isc-dhcp-client:${hostarch} |
4998 | + fi |
4999 | + |
5000 | + # rmdir /dev/shm for containers that have /run/shm |