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