Merge lp:~ubuntu-branches/ubuntu/quantal/lxc/quantal-201209142015 into lp:ubuntu/quantal/lxc

Proposed by Ubuntu Package Importer
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
Reviewer Review Type Date Requested Status
Ubuntu branches Pending
Review via email: mp+124511@code.launchpad.net

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://bugs.launchpad.net/udd linking to this merge proposal.

(this is an automatically generated message)

To post a comment you must log in.

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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
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
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches