Merge lp:~ubuntu-branches/ubuntu/quantal/lxc/quantal-201209062137 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-201209062137
Merge into: lp:ubuntu/quantal/lxc
Diff against target: 27328 lines (+26999/-0) (has conflicts)
48 files modified
.pc/0206-lxc-wait-initialize-timeout/src/lxc/lxc_wait.c (+99/-0)
.pc/0207-ubuntu-cloud-fixes.patch/templates/lxc-ubuntu-cloud.in (+401/-0)
.pc/0208-fix-getitem-utsname-segv/src/lxc/conf.c (+2467/-0)
.pc/0208-fix-getitem-utsname-segv/src/lxc/confile.c (+1670/-0)
.pc/0209-reload-conf-after-create/src/lxc/conf.c (+2467/-0)
.pc/0209-reload-conf-after-create/src/lxc/conf.h (+261/-0)
.pc/0209-reload-conf-after-create/src/lxc/lxccontainer.c (+917/-0)
.pc/0210-fix-debian-templates/templates/lxc-debian.in (+341/-0)
.pc/0210-fix-debian-templates/templates/lxc-lenny.in (+318/-0)
.pc/0211-add-hooks-to-manpage/doc/lxc.conf.sgml.in (+797/-0)
.pc/0212-lxc-destroy-rm-symlink/src/lxc/lxc-destroy.in (+126/-0)
.pc/0213-add-premount-hook.patch/doc/lxc.conf.sgml.in (+876/-0)
.pc/0213-add-premount-hook.patch/src/lxc/conf.c (+2485/-0)
.pc/0213-add-premount-hook.patch/src/lxc/conf.h (+262/-0)
.pc/0213-add-premount-hook.patch/src/lxc/confile.c (+1670/-0)
.pc/compilecleanups/0001-replace-HOOK-define-with-proper-code.patch/src/lxc/conf.c (+2464/-0)
.pc/compilecleanups/0001-replace-HOOK-define-with-proper-code.patch/src/lxc/conf.h (+266/-0)
.pc/compilecleanups/0001-replace-HOOK-define-with-proper-code.patch/src/lxc/start.c (+849/-0)
.pc/compilecleanups/0002-add-prototype-for-clone-2-as-per-manpage.patch/src/lxc/namespace.h (+56/-0)
.pc/compilecleanups/0003-check-chdir-return-value.patch/src/lxc/lxccontainer.c (+914/-0)
.pc/compilecleanups/0004-Fix-passing-non-const-char-in-for-const-char.patch/src/lxc/lxc.h (+210/-0)
.pc/compilecleanups/0004-Fix-passing-non-const-char-in-for-const-char.patch/src/lxc/lxc_wait.c (+100/-0)
.pc/compilecleanups/0004-Fix-passing-non-const-char-in-for-const-char.patch/src/lxc/lxccontainer.c (+917/-0)
.pc/compilecleanups/0004-Fix-passing-non-const-char-in-for-const-char.patch/src/lxc/lxccontainer.h (+71/-0)
.pc/compilecleanups/0004-Fix-passing-non-const-char-in-for-const-char.patch/src/tests/containertests.c (+257/-0)
.pc/compilecleanups/0005-return-nonvoid/src/lxc/conf.c (+2467/-0)
.pc/compilecleanups/0006-unused-var/src/lxc/confile.c (+1670/-0)
.pc/compilecleanups/0006-unused-var/src/lxc/lxc_wait.c (+100/-0)
.pc/compilecleanups/0006-unused-var/src/tests/getkeys.c (+71/-0)
.pc/compilecleanups/0007-tests-check-return-values/src/tests/containertests.c (+257/-0)
.pc/compilecleanups/0007-tests-check-return-values/src/tests/startone.c (+202/-0)
debian/changelog (+37/-0)
debian/hooks/mountecryptfsroot (+53/-0)
debian/patches/0206-lxc-wait-initialize-timeout (+18/-0)
debian/patches/0207-ubuntu-cloud-fixes.patch (+165/-0)
debian/patches/0208-fix-getitem-utsname-segv (+17/-0)
debian/patches/0209-reload-conf-after-create (+92/-0)
debian/patches/0210-fix-debian-templates (+27/-0)
debian/patches/0211-add-hooks-to-manpage (+94/-0)
debian/patches/0212-lxc-destroy-rm-symlink (+28/-0)
debian/patches/0213-add-premount-hook.patch (+80/-0)
debian/patches/compilecleanups/0001-replace-HOOK-define-with-proper-code.patch (+85/-0)
debian/patches/compilecleanups/0002-add-prototype-for-clone-2-as-per-manpage.patch (+28/-0)
debian/patches/compilecleanups/0003-check-chdir-return-value.patch (+29/-0)
debian/patches/compilecleanups/0004-Fix-passing-non-const-char-in-for-const-char.patch (+77/-0)
debian/patches/compilecleanups/0005-return-nonvoid (+13/-0)
debian/patches/compilecleanups/0006-unused-var (+48/-0)
debian/patches/compilecleanups/0007-tests-check-return-values (+80/-0)
Conflict adding file .pc/0206-lxc-wait-initialize-timeout.  Moved existing file to .pc/0206-lxc-wait-initialize-timeout.moved.
Conflict adding file .pc/0207-ubuntu-cloud-fixes.patch.  Moved existing file to .pc/0207-ubuntu-cloud-fixes.patch.moved.
Conflict adding file .pc/0208-fix-getitem-utsname-segv.  Moved existing file to .pc/0208-fix-getitem-utsname-segv.moved.
Conflict adding file .pc/0209-reload-conf-after-create.  Moved existing file to .pc/0209-reload-conf-after-create.moved.
Conflict adding file .pc/0210-fix-debian-templates.  Moved existing file to .pc/0210-fix-debian-templates.moved.
Conflict adding file .pc/0211-add-hooks-to-manpage.  Moved existing file to .pc/0211-add-hooks-to-manpage.moved.
Conflict adding file .pc/0212-lxc-destroy-rm-symlink.  Moved existing file to .pc/0212-lxc-destroy-rm-symlink.moved.
Conflict adding file .pc/0213-add-premount-hook.patch.  Moved existing file to .pc/0213-add-premount-hook.patch.moved.
Conflict adding file .pc/compilecleanups.  Moved existing file to .pc/compilecleanups.moved.
Text conflict in debian/changelog
Conflict adding file debian/hooks/mountecryptfsroot.  Moved existing file to debian/hooks/mountecryptfsroot.moved.
Conflict adding file debian/patches/0206-lxc-wait-initialize-timeout.  Moved existing file to debian/patches/0206-lxc-wait-initialize-timeout.moved.
Conflict adding file debian/patches/0207-ubuntu-cloud-fixes.patch.  Moved existing file to debian/patches/0207-ubuntu-cloud-fixes.patch.moved.
Conflict adding file debian/patches/0208-fix-getitem-utsname-segv.  Moved existing file to debian/patches/0208-fix-getitem-utsname-segv.moved.
Conflict adding file debian/patches/0209-reload-conf-after-create.  Moved existing file to debian/patches/0209-reload-conf-after-create.moved.
Conflict adding file debian/patches/0210-fix-debian-templates.  Moved existing file to debian/patches/0210-fix-debian-templates.moved.
Conflict adding file debian/patches/0211-add-hooks-to-manpage.  Moved existing file to debian/patches/0211-add-hooks-to-manpage.moved.
Conflict adding file debian/patches/0212-lxc-destroy-rm-symlink.  Moved existing file to debian/patches/0212-lxc-destroy-rm-symlink.moved.
Conflict adding file debian/patches/0213-add-premount-hook.patch.  Moved existing file to debian/patches/0213-add-premount-hook.patch.moved.
Conflict adding file debian/patches/compilecleanups.  Moved existing file to debian/patches/compilecleanups.moved.
To merge this branch: bzr merge lp:~ubuntu-branches/ubuntu/quantal/lxc/quantal-201209062137
Reviewer Review Type Date Requested Status
Ubuntu branches Pending
Review via email: mp+123180@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-201209062137. 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

162. By Serge Hallyn

fix example ecryptfs hook

161. By Serge Hallyn

add example ecryptfs hook

160. By Serge Hallyn

0213-add-premount-hook.patch: add a premount hook to support encrypted
filesystems. (LP: #1043052)

159. By Stéphane Graber

Make iptables call more consistent

158. By Serge Hallyn

0212-lxc-destroy-rm-symlink: If rootfs is a symbolic link to a directory,
remove it.

157. By Serge Hallyn

0211-add-hooks-to-manpage: document lxc.hook in the lxc.conf manpage.

156. By Stéphane Graber

Add Debian template fixes

155. By Serge Hallyn

not complete - fix one more out of 3 errors

154. By Serge Hallyn

fix typo

153. By Serge Hallyn

0209-reload-conf-after-create: add ability to free a lxc_conf. Use that
after calling Container->Create() to completely reload the newly created
config.

Preview Diff

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

Subscribers

People subscribed via source and target branches