Merge lp:~ubuntu-branches/ubuntu/quantal/lxc/quantal-201209062137 into lp:ubuntu/quantal/lxc
- Quantal (12.10)
- quantal-201209062137
- Merge into quantal
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 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu branches | Pending | ||
Review via email: mp+123180@code.launchpad.net |
Commit message
Description of the change
The package importer has detected a possible inconsistency between the package history in the archive and the history in bzr. As the archive is authoritative the importer has made lp:ubuntu/quantal/lxc reflect what is in the archive and the old bzr branch has been pushed to lp:~ubuntu-branches/ubuntu/quantal/lxc/quantal-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:/
(this is an automatically generated message)
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
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); |