Merge lp:~ubuntu-branches/ubuntu/precise/lxc/precise-201203021506 into lp:ubuntu/precise/lxc

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

Description of the change

The package importer has detected a possible inconsistency between the package history in the archive and the history in bzr. As the archive is authoritative the importer has made lp:ubuntu/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://bugs.launchpad.net/udd linking to this merge proposal.

(this is an automatically generated message)

To post a comment you must log in.

Unmerged revisions

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

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== added directory '.pc/0050-clone-lvm-sizes'
=== renamed directory '.pc/0050-clone-lvm-sizes' => '.pc/0050-clone-lvm-sizes.moved'
=== added file '.pc/0050-clone-lvm-sizes/.timestamp'
=== added directory '.pc/0050-clone-lvm-sizes/src'
=== added directory '.pc/0050-clone-lvm-sizes/src/lxc'
=== added file '.pc/0050-clone-lvm-sizes/src/lxc/lxc-clone.in'
--- .pc/0050-clone-lvm-sizes/src/lxc/lxc-clone.in 1970-01-01 00:00:00 +0000
+++ .pc/0050-clone-lvm-sizes/src/lxc/lxc-clone.in 2012-03-02 15:11:19 +0000
@@ -0,0 +1,247 @@
1#!/bin/bash
2
3#
4# lxc: linux Container library
5
6# Authors:
7# Serge Hallyn <serge.hallyn@ubuntu.com>
8# Daniel Lezcano <daniel.lezcano@free.fr>
9
10# This library is free software; you can redistribute it and/or
11# modify it under the terms of the GNU Lesser General Public
12# License as published by the Free Software Foundation; either
13# version 2.1 of the License, or (at your option) any later version.
14
15# This library is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18# Lesser General Public License for more details.
19
20# You should have received a copy of the GNU Lesser General Public
21# License along with this library; if not, write to the Free Software
22# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
24usage() {
25 echo "usage: lxc-clone -o <orig> -n <new> [-s] [-h] [-L fssize] [-v vgname]"
26}
27
28help() {
29 usage
30 echo
31 echo "creates a lxc system object."
32 echo
33 echo "Options:"
34 echo "orig : name of the original container"
35 echo "new : name of the new container"
36 echo "-s : make the new rootfs a snapshot of the original"
37 echo "fssize : size if creating a new fs. By default, 2G"
38 echo "vgname : lvm volume group name, lxc by default"
39}
40
41shortoptions='ho:n:sL:v:'
42longoptions='help,orig:,name:,snapshot,fssize,vgname'
43lxc_path=/var/lib/lxc
44bindir=/usr/bin
45snapshot=no
46lxc_size=2G
47lxc_vg=lxc
48
49getopt=$(getopt -o $shortoptions --longoptions $longoptions -- "$@")
50if [ $? != 0 ]; then
51 usage
52 exit 1;
53fi
54
55eval set -- "$getopt"
56
57while true; do
58 case "$1" in
59 -h|--help)
60 help
61 exit 1
62 ;;
63 -s|--snapshot)
64 shift
65 snapshot=yes
66 ;;
67 -o|--orig)
68 shift
69 lxc_orig=$1
70 shift
71 ;;
72 -L|--fssize)
73 shift
74 lxc_size=$1
75 shift
76 ;;
77 -v|--vgname)
78 shift
79 lxc_vg=$1
80 shift
81 ;;
82 -n|--new)
83 shift
84 lxc_new=$1
85 shift
86 ;;
87 --)
88 shift
89 break;;
90 *)
91 echo $1
92 usage
93 exit 1
94 ;;
95 esac
96done
97
98if [ -z "$lxc_path" ]; then
99 echo "no configuration path defined !"
100 exit 1
101fi
102
103if [ ! -r $lxc_path ]; then
104 echo "configuration path '$lxc_path' not found"
105 exit 1
106fi
107
108if [ -z "$lxc_orig" ]; then
109 echo "no original container name specified"
110 usage
111 exit 1
112fi
113
114if [ -z "$lxc_new" ]; then
115 echo "no new container name specified"
116 usage
117 exit 1
118fi
119
120if [ "$(id -u)" != "0" ]; then
121 echo "This command has to be run as root"
122 exit 1
123fi
124
125if [ ! -r $lxc_path ]; then
126 echo "no configuration path defined !"
127 exit 1
128fi
129
130if [ ! -d "$lxc_path/$lxc_orig" ]; then
131 echo "'$lxc_orig' does not exist"
132 exit 1
133fi
134
135if [ -d "$lxc_path/$lxc_new" ]; then
136 echo "'$lxc_new' already exists"
137 exit 1
138fi
139
140hostname=$lxc_new
141mkdir -p $lxc_path/$lxc_new
142
143echo "Tweaking configuration"
144cp $lxc_path/$lxc_orig/config $lxc_path/$lxc_new/config
145sed -i '/lxc.utsname/d' $lxc_path/$lxc_new/config
146echo "lxc.utsname = $hostname" >> $lxc_path/$lxc_new/config
147
148sed -i '/lxc.mount/d' $lxc_path/$lxc_new/config
149echo "lxc.mount = $lxc_path/$lxc_new/fstab" >> $lxc_path/$lxc_new/config
150
151cp $lxc_path/$lxc_orig/fstab $lxc_path/$lxc_new/fstab
152sed -i "s@$lxc_path/$lxc_orig@$lxc_path/$lxc_new@" $lxc_path/$lxc_new/fstab
153
154rootfs=$lxc_path/$lxc_new/rootfs
155# First figure out if the old is a device. For now we only support
156# lvm devices.
157mounted=0
158sed -i '/lxc.rootfs/d' $lxc_path/$lxc_new/config
159oldroot=`grep lxc.rootfs $lxc_path/$lxc_orig/config | awk -F= '{ print $2 '}`
160
161cleanup() {
162 if [ -b $oldroot ]; then
163 if [ $mounted -eq 1 ]; then
164 umount $rootfs
165 fi
166 lvremove -f $rootdev
167 fi
168 ${bindir}/lxc-destroy -n $lxc_new
169 echo aborted
170 exit 1
171}
172trap cleanup SIGHUP SIGINT SIGTERM
173
174echo "Copying rootfs..."
175if [ -b $oldroot ]; then
176 which vgscan > /dev/null
177 if [ $? -ne 0 ]; then
178 echo "vgscan not found. Please install lvm2 package"
179 exit 1
180 fi
181
182 # this is a device. If we don't want to snapshot, then mkfs, mount
183 # and rsync. Trivial but not yet implemented
184 if [ $snapshot == "no" ]; then
185 echo "non-snapshot and non-lvm clone of block device not yet implemented"
186 exit 1
187 fi
188 lvdisplay $oldroot > /dev/null 2>&1
189 if [ $? -ne 0 ]; then
190 echo "non-snapshot and non-lvm clone of block device not yet implemented"
191 exit 1
192 fi
193 # ok, create a snapshot of the lvm device
194 lvcreate -s -L $lxc_size -n $lxc_new /dev/$lxc_vg/$lxc_orig || cleanup
195 echo "lxc.rootfs = /dev/$lxc_vg/$lxc_new" >> $lxc_path/$lxc_new/config
196 # and mount it so we can tweak it
197 mkdir -p $lxc_path/$lxc_new/rootfs
198 mount /dev/$lxc_vg/$lxc_new $rootfs || { echo "failed to mount new rootfs"; cleanup; }
199 mounted=1
200elif out=$(btrfs subvolume list "$lxc_path/$lxc_orig/rootfs" 2>&1); then
201 out=$(btrfs subvolume snapshot "$lxc_path/$lxc_orig/rootfs" "$rootfs" 2>&1)
202 if [ $? -ne 0 ]; then
203 echo "failed btrfs subvolume snapshot of $lxc_path/$lxc_orig/rootfs"
204 cleanup
205 fi
206 echo "lxc.rootfs = $rootfs" >> "$lxc_path/$lxc_new/config"
207else
208 cp -a $lxc_path/$lxc_orig/rootfs $lxc_path/$lxc_new/rootfs || cleanup
209 echo "lxc.rootfs = $rootfs" >> $lxc_path/$lxc_new/config
210fi
211
212echo "Updating rootfs..."
213
214# so you can 'ssh $hostname.' or 'ssh $hostname.local'
215if [ -f $rootfs/etc/dhcp/dhclient.conf ]; then
216 sed -i "s/send host-name.*$/send host-name $hostname;/" $rootfs/etc/dhcp/dhclient.conf
217fi
218
219c=$lxc_path/$lxc_new/config
220# change hwaddrs
221mv ${c} ${c}.old
222(
223while read line; do
224 if [ "${line:0:18}" = "lxc.network.hwaddr" ]; then
225 echo "lxc.network.hwaddr= 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')"
226 else
227 echo $line
228 fi
229done
230) < ${c}.old > ${c}
231rm -f ${c}.old
232
233# set the hostname
234cat <<EOF > $rootfs/etc/hostname
235$hostname
236EOF
237# set minimal hosts
238cat <<EOF > $rootfs/etc/hosts
239127.0.0.1 localhost $hostname
240EOF
241
242# if this was a block device, then umount it now
243if [ $mounted -eq 1 ]; then
244 umount $rootfs
245fi
246
247echo "'$lxc_new' created"
0248
=== added directory '.pc/0051-lxc-create-lvm-use-1G'
=== renamed directory '.pc/0051-lxc-create-lvm-use-1G' => '.pc/0051-lxc-create-lvm-use-1G.moved'
=== added file '.pc/0051-lxc-create-lvm-use-1G/.timestamp'
=== added directory '.pc/0051-lxc-create-lvm-use-1G/src'
=== added directory '.pc/0051-lxc-create-lvm-use-1G/src/lxc'
=== added file '.pc/0051-lxc-create-lvm-use-1G/src/lxc/lxc-create.in'
--- .pc/0051-lxc-create-lvm-use-1G/src/lxc/lxc-create.in 1970-01-01 00:00:00 +0000
+++ .pc/0051-lxc-create-lvm-use-1G/src/lxc/lxc-create.in 2012-03-02 15:11:19 +0000
@@ -0,0 +1,295 @@
1#!/bin/bash
2
3#
4# lxc: linux Container library
5
6# Authors:
7# Daniel Lezcano <daniel.lezcano@free.fr>
8
9# This library is free software; you can redistribute it and/or
10# modify it under the terms of the GNU Lesser General Public
11# License as published by the Free Software Foundation; either
12# version 2.1 of the License, or (at your option) any later version.
13
14# This library is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17# Lesser General Public License for more details.
18
19# You should have received a copy of the GNU Lesser General Public
20# License along with this library; if not, write to the Free Software
21# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22
23usage() {
24 echo "usage: lxc-create -n <name> [-f configuration] [-t template] [-h] -- [template_options]"
25 echo "usage: lxc-create -n <name> [-f configuration] [-t template] [-h] [fsopts] -- [template_options]"
26 echo " fsopts: -B none"
27 echo " fsopts: -B lvm [--lvname lvname] [--vgname vgname] [--fstype fstype] [--fssize fssize]"
28 echo " fsopts: -B btrfs"
29 echo " flag is not necessary, if possible btrfs support will be used"
30# echo " fsopts: -B union [--uniontype overlayfs]"
31# echo " fsopts: -B loop [--fstype fstype] [--fssize fssize]"
32# echo " fsopts: -B qemu-nbd [--type qed|qcow2|raw] [--fstype fstype] [--fssize fssize] # Qemu qed disk format"
33}
34
35
36help() {
37 usage
38 echo
39 echo "creates a lxc system object."
40 echo
41 echo "Options:"
42 echo "name : name of the container"
43 echo "configuration: lxc configuration"
44 echo "template : lxc-template is an accessible template script"
45 echo
46 echo "The container backing store can be altered using '-B'. By default it"
47 echo "is 'none', which is a simple directory tree under /var/lib/lxc/<name>/rootfs"
48 echo "Otherwise, the following option values may be relevant:"
49 echo "lvname : [for -lvm] name of lv in which to create lv,"
50 echo " container-name by default"
51 echo "vgname : [for -lvm] name of vg in which to create lv, 'lxc' by default"
52 echo "fstype : name of filesystem to create, ext4 by default"
53 echo "fssize : size of filesystem to create, 500M by default"
54 if [ -z $lxc_template ]; then
55 echo "for template-specific help, specify a template, for instance:"
56 echo "lxc-create -t ubuntu -h"
57 exit 0
58 fi
59 type ${templatedir}/lxc-$lxc_template >/dev/null
60 echo
61 echo "template-specific help follows: (these options follow '--')"
62 if [ $? -eq 0 ]; then
63 ${templatedir}/lxc-$lxc_template -h
64 fi
65}
66
67shortoptions='hn:f:t:B:'
68longoptions='help,name:,config:,template:,backingstore:,fstype:,lvname:,vgname:,fssize:'
69lxc_path=@LXCPATH@
70bindir=@BINDIR@
71templatedir=@LXCTEMPLATEDIR@
72backingstore=_unset
73fstype=ext4
74fssize=500M
75vgname=lxc
76
77getopt=$(getopt -o $shortoptions --longoptions $longoptions -- "$@")
78if [ $? != 0 ]; then
79 usage
80 exit 1;
81fi
82
83eval set -- "$getopt"
84
85while true; do
86 case "$1" in
87 -h|--help)
88 help
89 exit 1
90 ;;
91 -n|--name)
92 shift
93 lxc_name=$1
94 shift
95 ;;
96 -f|--config)
97 shift
98 lxc_config=$1
99 shift
100 ;;
101 -t|--template)
102 shift
103 lxc_template=$1
104 shift
105 ;;
106 -B|--backingstore)
107 shift
108 backingstore=$1
109 shift
110 ;;
111 --lvname)
112 shift
113 lvname=$1
114 shift
115 ;;
116 --vgname)
117 shift
118 vgname=$1
119 shift
120 ;;
121 --fstype)
122 shift
123 fstype=$1
124 shift
125 ;;
126 --fssize)
127 shift
128 fssize=$1
129 shift
130 ;;
131 --)
132 shift
133 break;;
134 *)
135 echo $1
136 usage
137 exit 1
138 ;;
139 esac
140done
141
142if [ -z "$lxc_path" ]; then
143 echo "no configuration path defined !"
144 exit 1
145fi
146
147if [ ! -r $lxc_path ]; then
148 echo "configuration path '$lxc_path' not found"
149 exit 1
150fi
151
152if [ -z "$lxc_name" ]; then
153 echo "no container name specified"
154 usage
155 exit 1
156fi
157
158if [ -z "$lvname" ]; then
159 lvname="$lxc_name"
160fi
161
162if [ "$(id -u)" != "0" ]; then
163 echo "This command has to be run as root"
164 exit 1
165fi
166
167case "$backingstore" in
168 lvm|none|btrfs|_unset) :;;
169 *) echo "'$backingstore' is not known ('none', 'lvm', 'btrfs')"
170 usage
171 exit 1
172 ;;
173esac
174
175if [ -d "$lxc_path/$lxc_name" ]; then
176 echo "'$lxc_name' already exists"
177 exit 1
178fi
179
180rootfs="$lxc_path/$lxc_name/rootfs"
181
182if [ "$backingstore" = "_unset" -o "$backingstore" = "btrfs" ]; then
183 # if no backing store was given, then see if btrfs would work
184 if which btrfs >/dev/null 2>&1 &&
185 btrfs filesystem df "$lxc_path/" >/dev/null 2>&1; then
186 backingstore="btrfs"
187 else
188 if [ "$backingstore" = "btrfs" ]; then
189 echo "missing 'btrfs' command or $lxc_path is not btrfs";
190 exit 1;
191 fi
192 backingstore="none"
193 fi
194fi
195
196if [ $backingstore = "lvm" ]; then
197 which vgscan > /dev/null
198 if [ $? -ne 0 ]; then
199 echo "vgscan not found. Please install lvm2 package"
200 exit 1
201 fi
202 grep -q "\<$fstype\>" /proc/filesystems
203 if [ $? -ne 0 ]; then
204 echo "$fstype is not listed in /proc/filesystems"
205 usage
206 exit 1
207 fi
208
209 vgscan | grep -q "Found volume group \"$vgname\""
210 if [ $? -ne 0 ]; then
211 echo "Could not find volume group \"$vgname\""
212 usage
213 exit 1
214 fi
215
216 rootdev=/dev/$vgname/$lvname
217 lvdisplay $rootdev > /dev/null 2>&1
218 if [ $? -eq 0 ]; then
219 echo "backing store already exists: $rootdev"
220 echo "please delete it (using \"lvremove $rootdev\") and try again"
221 exit 1
222 fi
223elif [ "$backingstore" = "btrfs" ]; then
224 mkdir "$lxc_path/$lxc_name"
225 if ! out=$(btrfs subvolume create "$rootfs" 2>&1); then
226 echo "failed to create subvolume in $rootfs: $out";
227 exit 1;
228 fi
229fi
230
231cleanup() {
232 if [ $backingstore = "lvm" ]; then
233 umount $rootfs
234 lvremove -f $rootdev
235 fi
236 ${bindir}/lxc-destroy -n $lxc_name
237 echo aborted
238 exit 1
239}
240
241trap cleanup SIGHUP SIGINT SIGTERM
242
243mkdir -p $lxc_path/$lxc_name
244
245if [ -z "$lxc_config" ]; then
246 echo
247 echo "No config file specified, using the default config"
248 lxc_config="/etc/lxc/lxc.conf"
249fi
250
251if [ ! -r "$lxc_config" ]; then
252 echo "'$lxc_config' configuration file not found"
253 exit 1
254fi
255
256cp $lxc_config $lxc_path/$lxc_name/config
257
258# Create the fs as needed
259[ -d "$rootfs" ] || mkdir "$rootfs"
260if [ $backingstore = "lvm" ]; then
261 lvcreate -L $fssize -n $lvname $vgname || exit 1
262 udevadm settle
263 mkfs -t $fstype $rootdev || exit 1
264 mount -t $fstype $rootdev $rootfs
265fi
266
267
268if [ ! -z $lxc_template ]; then
269
270 type ${templatedir}/lxc-$lxc_template >/dev/null
271 if [ $? -ne 0 ]; then
272 echo "unknown template '$lxc_template'"
273 cleanup
274 fi
275
276 ${templatedir}/lxc-$lxc_template --path=$lxc_path/$lxc_name --name=$lxc_name $*
277 if [ $? -ne 0 ]; then
278 echo "failed to execute template '$lxc_template'"
279 cleanup
280 fi
281
282 echo "'$lxc_template' template installed"
283fi
284
285if [ $backingstore = "lvm" ]; then
286 echo "Unmounting LVM"
287 umount $rootfs
288
289 # TODO: make the templates set this right from the start
290 sed -i '/lxc.rootfs/d' $lxc_path/$lxc_name/config
291 echo "lxc.rootfs = $rootdev" >> $lxc_path/$lxc_name/config
292fi
293
294
295echo "'$lxc_name' created"
0296
=== added directory '.pc/0052-ubuntu-bind-user-conflict'
=== renamed directory '.pc/0052-ubuntu-bind-user-conflict' => '.pc/0052-ubuntu-bind-user-conflict.moved'
=== added file '.pc/0052-ubuntu-bind-user-conflict/.timestamp'
=== added directory '.pc/0052-ubuntu-bind-user-conflict/templates'
=== added file '.pc/0052-ubuntu-bind-user-conflict/templates/lxc-ubuntu.in'
--- .pc/0052-ubuntu-bind-user-conflict/templates/lxc-ubuntu.in 1970-01-01 00:00:00 +0000
+++ .pc/0052-ubuntu-bind-user-conflict/templates/lxc-ubuntu.in 2012-03-02 15:11:19 +0000
@@ -0,0 +1,645 @@
1#!/bin/bash
2
3#
4# template script for generating ubuntu container for LXC
5#
6# This script consolidates and extends the existing lxc ubuntu scripts
7#
8
9# Copyright © 2011 Serge Hallyn <serge.hallyn@canonical.com>
10# Copyright © 2010 Wilhelm Meier
11# Author: Wilhelm Meier <wilhelm.meier@fh-kl.de>
12#
13# This program is free software; you can redistribute it and/or modify
14# it under the terms of the GNU General Public License version 2, as
15# published by the Free Software Foundation.
16
17# This program is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20# GNU General Public License for more details.
21
22# You should have received a copy of the GNU General Public License along
23# with this program; if not, write to the Free Software Foundation, Inc.,
24# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25#
26
27set -e
28
29if [ -r /etc/default/lxc ]; then
30 . /etc/default/lxc
31fi
32
33configure_ubuntu()
34{
35 rootfs=$1
36 hostname=$2
37 release=$3
38
39 # configure the network using the dhcp
40 cat <<EOF > $rootfs/etc/network/interfaces
41auto lo
42iface lo inet loopback
43
44auto eth0
45iface eth0 inet dhcp
46EOF
47
48 # set the hostname
49 cat <<EOF > $rootfs/etc/hostname
50$hostname
51EOF
52 # set minimal hosts
53 cat <<EOF > $rootfs/etc/hosts
54127.0.0.1 localhost $hostname
55EOF
56
57 if [ "$release" = "precise" ]; then
58 groups="sudo"
59 else
60 groups="sudo admin"
61
62 # suppress log level output for udev
63 sed -i "s/=\"err\"/=0/" $rootfs/etc/udev/udev.conf
64
65 # remove jobs for consoles 5 and 6 since we only create 4 consoles in
66 # this template
67 rm -f $rootfs/etc/init/tty{5,6}.conf
68 fi
69
70 chroot $rootfs useradd --create-home -s /bin/bash ubuntu
71 echo "ubuntu:ubuntu" | chroot $rootfs chpasswd
72
73 for group in $groups; do
74 chroot $rootfs groupadd --system $group >/dev/null 2>&1 || true
75 chroot $rootfs adduser ubuntu $group >/dev/null 2>&1 || true
76 done
77
78 if [ -n "$auth_key" -a -f "$auth_key" ]; then
79 u_path="/home/ubuntu/.ssh"
80 root_u_path="$rootfs/$u_path"
81 mkdir -p $root_u_path
82 cp $auth_key "$root_u_path/authorized_keys"
83 chroot $rootfs chown -R ubuntu: "$u_path"
84
85 echo "Inserted SSH public key from $auth_key into /home/ubuntu/.ssh/authorized_keys"
86 fi
87 return 0
88}
89
90write_sourceslist()
91{
92 # $1 => path to the rootfs
93 # $2 => architecture we want to add
94 # $3 => whether to use the multi-arch syntax or not
95
96 case $2 in
97 amd64|i386)
98 MIRROR=${MIRROR:-http://archive.ubuntu.com/ubuntu}
99 SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.ubuntu.com/ubuntu}
100 ;;
101 sparc)
102 case $SUITE in
103 gutsy)
104 MIRROR=${MIRROR:-http://archive.ubuntu.com/ubuntu}
105 SECURITY_MIRROR=${SECURITY_MIRRORMIRROR:-http://security.ubuntu.com/ubuntu}
106 ;;
107 *)
108 MIRROR=${MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
109 SECURITY_MIRROR=${SECURITY_MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
110 ;;
111 esac
112 ;;
113 *)
114 MIRROR=${MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
115 SECURITY_MIRROR=${SECURITY_MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
116 ;;
117 esac
118 if [ -n "$3" ]; then
119 cat >> "$1/etc/apt/sources.list" << EOF
120deb [arch=$2] $MIRROR ${release} main restricted universe multiverse
121deb [arch=$2] $MIRROR ${release}-updates main restricted universe multiverse
122deb [arch=$2] $SECURITY_MIRROR ${release}-security main restricted universe multiverse
123EOF
124 else
125 cat >> "$1/etc/apt/sources.list" << EOF
126deb $MIRROR ${release} main restricted universe multiverse
127deb $MIRROR ${release}-updates main restricted universe multiverse
128deb $SECURITY_MIRROR ${release}-security main restricted universe multiverse
129EOF
130 fi
131}
132
133download_ubuntu()
134{
135 cache=$1
136 arch=$2
137 release=$3
138
139 if [ $release = "lucid" ]; then
140 packages=dialog,apt,apt-utils,resolvconf,iproute,inetutils-ping,vim,dhcp3-client,ssh,lsb-release,gnupg
141 elif [ $release = "maverick" ]; then
142 packages=dialog,apt,apt-utils,resolvconf,iproute,inetutils-ping,vim,dhcp3-client,ssh,lsb-release,gnupg,netbase
143 elif [ $release = "natty" ]; then
144 packages=dialog,apt,apt-utils,resolvconf,iproute,inetutils-ping,vim,isc-dhcp-client,isc-dhcp-common,ssh,lsb-release,gnupg,netbase
145 else
146 packages=dialog,apt,apt-utils,iproute,inetutils-ping,vim,isc-dhcp-client,isc-dhcp-common,ssh,lsb-release,gnupg,netbase,ubuntu-keyring
147 fi
148 echo "installing packages: $packages"
149
150 # check the mini ubuntu was not already downloaded
151 mkdir -p "$cache/partial-$arch"
152 if [ $? -ne 0 ]; then
153 echo "Failed to create '$cache/partial-$arch' directory"
154 return 1
155 fi
156
157 # download a mini ubuntu into a cache
158 echo "Downloading ubuntu $release minimal ..."
159 if [ -n "$(which qemu-debootstrap)" ]; then
160 qemu-debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR
161 else
162 debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR
163 fi
164
165 if [ $? -ne 0 ]; then
166 echo "Failed to download the rootfs, aborting."
167 return 1
168 fi
169
170 # Serge isn't sure whether we should avoid doing this when
171 # $release == `distro-info -d`
172 echo "Installing updates"
173 > $cache/partial-$arch/etc/apt/sources.list
174 write_sourceslist $cache/partial-$arch/ $arch
175
176 chroot "$1/partial-${arch}" apt-get update
177 if [ $? -ne 0 ]; then
178 echo "Failed to update the apt cache"
179 return 1
180 fi
181 cat > "$1/partial-${arch}"/usr/sbin/policy-rc.d << EOF
182#!/bin/sh
183exit 101
184EOF
185 chmod +x "$1/partial-${arch}"/usr/sbin/policy-rc.d
186
187 lxc-unshare -s MOUNT -- chroot "$1/partial-${arch}" apt-get dist-upgrade -y
188 ret=$?
189 rm -f "$1/partial-${arch}"/usr/sbin/policy-rc.d
190
191 if [ $ret -ne 0 ]; then
192 echo "Failed to upgrade the cache"
193 return 1
194 fi
195
196 mv "$1/partial-$arch" "$1/rootfs-$arch"
197 echo "Download complete"
198 return 0
199}
200
201copy_ubuntu()
202{
203 cache=$1
204 arch=$2
205 rootfs=$3
206
207 # make a local copy of the miniubuntu
208 echo "Copying rootfs to $rootfs ..."
209 mkdir -p $rootfs
210 rsync -a $cache/rootfs-$arch/ $rootfs/ || return 1
211 return 0
212}
213
214install_ubuntu()
215{
216 rootfs=$1
217 release=$2
218 flushcache=$3
219 cache="/var/cache/lxc/$release"
220 mkdir -p /var/lock/subsys/
221 (
222 flock -n -x 200
223 if [ $? -ne 0 ]; then
224 echo "Cache repository is busy."
225 return 1
226 fi
227
228
229 if [ $flushcache -eq 1 ]; then
230 echo "Flushing cache..."
231 rm -rf "$cache/partial-$arch"
232 rm -rf "$cache/rootfs-$arch"
233 fi
234
235 echo "Checking cache download in $cache/rootfs-$arch ... "
236 if [ ! -e "$cache/rootfs-$arch" ]; then
237 download_ubuntu $cache $arch $release
238 if [ $? -ne 0 ]; then
239 echo "Failed to download 'ubuntu $release base'"
240 return 1
241 fi
242 fi
243
244 echo "Copy $cache/rootfs-$arch to $rootfs ... "
245 copy_ubuntu $cache $arch $rootfs
246 if [ $? -ne 0 ]; then
247 echo "Failed to copy rootfs"
248 return 1
249 fi
250
251 return 0
252
253 ) 200>/var/lock/subsys/lxc
254
255 return $?
256}
257
258copy_configuration()
259{
260 path=$1
261 rootfs=$2
262 name=$3
263 arch=$4
264 release=$5
265
266 if [ $arch = "i386" ]; then
267 arch="i686"
268 fi
269
270 ttydir=""
271 if [ $release = "precise" ]; then
272 ttydir=" lxc"
273 fi
274
275 # if there is exactly one veth network entry, make sure it has an
276 # associated hwaddr.
277 nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l`
278 if [ $nics -eq 1 ]; then
279 grep -q "^lxc.network.hwaddr" $path/config || cat <<EOF >> $path/config
280lxc.network.hwaddr= 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')
281EOF
282 fi
283
284 cat <<EOF >> $path/config
285lxc.utsname = $name
286
287lxc.devttydir =$ttydir
288lxc.tty = 4
289lxc.pts = 1024
290lxc.rootfs = $rootfs
291lxc.mount = $path/fstab
292lxc.arch = $arch
293lxc.cap.drop = sys_module mac_admin
294
295lxc.cgroup.devices.deny = a
296# Allow any mknod (but not using the node)
297lxc.cgroup.devices.allow = c *:* m
298lxc.cgroup.devices.allow = b *:* m
299# /dev/null and zero
300lxc.cgroup.devices.allow = c 1:3 rwm
301lxc.cgroup.devices.allow = c 1:5 rwm
302# consoles
303lxc.cgroup.devices.allow = c 5:1 rwm
304lxc.cgroup.devices.allow = c 5:0 rwm
305#lxc.cgroup.devices.allow = c 4:0 rwm
306#lxc.cgroup.devices.allow = c 4:1 rwm
307# /dev/{,u}random
308lxc.cgroup.devices.allow = c 1:9 rwm
309lxc.cgroup.devices.allow = c 1:8 rwm
310lxc.cgroup.devices.allow = c 136:* rwm
311lxc.cgroup.devices.allow = c 5:2 rwm
312# rtc
313lxc.cgroup.devices.allow = c 254:0 rwm
314#fuse
315lxc.cgroup.devices.allow = c 10:229 rwm
316#tun
317lxc.cgroup.devices.allow = c 10:200 rwm
318#full
319lxc.cgroup.devices.allow = c 1:7 rwm
320#hpet
321lxc.cgroup.devices.allow = c 10:228 rwm
322#kvm
323lxc.cgroup.devices.allow = c 10:232 rwm
324EOF
325
326 cat <<EOF > $path/fstab
327proc $rootfs/proc proc nodev,noexec,nosuid 0 0
328sysfs $rootfs/sys sysfs defaults 0 0
329EOF
330
331 if [ $? -ne 0 ]; then
332 echo "Failed to add configuration"
333 return 1
334 fi
335
336 return 0
337}
338
339trim()
340{
341 rootfs=$1
342 release=$2
343
344 # provide the lxc service
345 cat <<EOF > $rootfs/etc/init/lxc.conf
346# fake some events needed for correct startup other services
347
348description "Container Upstart"
349
350start on startup
351
352script
353 rm -rf /var/run/*.pid
354 rm -rf /var/run/network/*
355 /sbin/initctl emit stopped JOB=udevtrigger --no-wait
356 /sbin/initctl emit started JOB=udev --no-wait
357end script
358EOF
359
360 # fix buggus runlevel with sshd
361 cat <<EOF > $rootfs/etc/init/ssh.conf
362# ssh - OpenBSD Secure Shell server
363#
364# The OpenSSH server provides secure shell access to the system.
365
366description "OpenSSH server"
367
368start on filesystem
369stop on runlevel [!2345]
370
371expect fork
372respawn
373respawn limit 10 5
374umask 022
375# replaces SSHD_OOM_ADJUST in /etc/default/ssh
376oom never
377
378pre-start script
379 test -x /usr/sbin/sshd || { stop; exit 0; }
380 test -e /etc/ssh/sshd_not_to_be_run && { stop; exit 0; }
381 test -c /dev/null || { stop; exit 0; }
382
383 mkdir -p -m0755 /var/run/sshd
384end script
385
386# if you used to set SSHD_OPTS in /etc/default/ssh, you can change the
387# 'exec' line here instead
388exec /usr/sbin/sshd
389EOF
390
391 cat <<EOF > $rootfs/etc/init/console.conf
392# console - getty
393#
394# This service maintains a console on tty1 from the point the system is
395# started until it is shut down again.
396
397start on stopped rc RUNLEVEL=[2345]
398stop on runlevel [!2345]
399
400respawn
401exec /sbin/getty -8 38400 /dev/console
402EOF
403
404 cat <<EOF > $rootfs/lib/init/fstab
405# /lib/init/fstab: cleared out for bare-bones lxc
406EOF
407
408 # reconfigure some services
409 if [ -z "$LANG" ]; then
410 chroot $rootfs locale-gen en_US.UTF-8
411 chroot $rootfs update-locale LANG=en_US.UTF-8
412 else
413 chroot $rootfs locale-gen $LANG
414 chroot $rootfs update-locale LANG=$LANG
415 fi
416
417 # remove pointless services in a container
418 chroot $rootfs /usr/sbin/update-rc.d -f ondemand remove
419
420 chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls u*.conf); do mv $f $f.orig; done'
421 chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls tty[2-9].conf); do mv $f $f.orig; done'
422 chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls plymouth*.conf); do mv $f $f.orig; done'
423 chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls hwclock*.conf); do mv $f $f.orig; done'
424 chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls module*.conf); do mv $f $f.orig; done'
425
426 # if this isn't lucid, then we need to twiddle the network upstart bits :(
427 if [ $release != "lucid" ]; then
428 sed -i 's/^.*emission handled.*$/echo Emitting lo/' $rootfs/etc/network/if-up.d/upstart
429 fi
430}
431
432post_process()
433{
434 rootfs=$1
435 release=$2
436 trim_container=$3
437
438 if [ $trim_container -eq 1 ]; then
439 trim $rootfs $release
440 elif [ $release = "lucid" -o $release = "maverick" -o $release = "natty" \
441 -o $release = "oneiric" ]; then
442 # for lucid and maverick, if not trimming, then add the ubuntu-virt
443 # ppa and install lxcguest
444 if [ $release = "lucid" -o $release = "maverick" ]; then
445 chroot $rootfs apt-get install --force-yes -y python-software-properties
446 chroot $rootfs add-apt-repository ppa:ubuntu-virt/ppa
447 fi
448 cresolvonf="${rootfs}/etc/resolv.conf"
449 mv $cresolvonf ${cresolvonf}.lxcbak
450 cat /etc/resolv.conf > ${cresolvonf}
451 chroot $rootfs apt-get update
452 chroot $rootfs apt-get install --force-yes -y lxcguest
453 rm -f ${cresolvonf}
454 mv ${cresolvonf}.lxcbak ${cresolvonf}
455 fi
456
457 # If the container isn't running a native architecture, setup multiarch
458 if [ -x "$(ls -1 ${rootfs}/usr/bin/qemu-*-static 2>/dev/null)" ]; then
459 mkdir -p ${rootfs}/etc/dpkg/dpkg.cfg.d
460 echo "foreign-architecture ${hostarch}" > ${rootfs}/etc/dpkg/dpkg.cfg.d/lxc-multiarch
461
462 # Save existing value of MIRROR and SECURITY_MIRROR
463 DEFAULT_MIRROR=$MIRROR
464 DEFAULT_SECURITY_MIRROR=$SECURITY_MIRROR
465
466 # Write a new sources.list containing both native and multiarch entries
467 > ${rootfs}/etc/apt/sources.list
468 write_sourceslist $rootfs $arch "native"
469
470 MIRROR=$DEFAULT_MIRROR
471 SECURITY_MIRROR=$DEFAULT_SECURITY_MIRROR
472 write_sourceslist $rootfs $hostarch "multiarch"
473
474 # Finally update the lists and install upstart using the host architecture
475 chroot $rootfs apt-get update
476 chroot $rootfs apt-get install --force-yes -y --no-install-recommends upstart:${hostarch} mountall:amd64 iproute:amd64 isc-dhcp-client:amd64
477 fi
478}
479
480do_bindhome()
481{
482 rootfs=$1
483 user=$2
484
485 # copy /etc/passwd, /etc/shadow, and /etc/group entries into container
486 pwd=`getent passwd $user` || { echo "Failed to copy password entry for $user"; false; }
487 echo $pwd >> $rootfs/etc/passwd
488
489 # make sure user's shell exists in the container
490 shell=`echo $pwd | cut -d: -f 7`
491 if [ ! -x $rootfs/$shell ]; then
492 echo "shell $shell for user $user was not found in the container."
493 pkg=`dpkg -S $(readlink -m $shell) | cut -d ':' -f1`
494 echo "Installing $pkg"
495 chroot $rootfs apt-get --force-yes -y install $pkg
496 fi
497
498 shad=`getent shadow $user`
499 echo "$shad" >> $rootfs/etc/shadow
500
501 # bind-mount the user's path into the container's /home
502 h=`getent passwd $user | cut -d: -f 6`
503 mkdir -p $rootfs/$h
504 echo "$h $rootfs/$h none bind 0 0" >> $path/fstab
505
506 # Make sure the group exists in container
507 chroot $rootfs getent group $user || { \
508 grp=`getent group $user`
509 echo "$grp" >> $rootfs/etc/group
510 }
511}
512
513usage()
514{
515 cat <<EOF
516$1 -h|--help [-a|--arch] [-b|--bindhome <user>] [--trim]
517 [-F | --flush-cache] [-r|--release <release>] [ -S | --auth-key <keyfile>]
518release: lucid | maverick | natty | oneiric | precise
519trim: make a minimal (faster, but not upgrade-safe) container
520bindhome: bind <user>'s home into the container
521arch: amd64 or i386: defaults to host arch
522auth-key: SSH Public key file to inject into container
523EOF
524 return 0
525}
526
527options=$(getopt -o a:b:hp:r:xn:FS: -l arch:,bindhome:,help,path:,release:,trim,name:,flush-cache,auth-key: -- "$@")
528if [ $? -ne 0 ]; then
529 usage $(basename $0)
530 exit 1
531fi
532eval set -- "$options"
533
534release=lucid
535if [ -f /etc/lsb-release ]; then
536 . /etc/lsb-release
537 case "$DISTRIB_CODENAME" in
538 lucid|maverick|natty|oneiric|precise)
539 release=$DISTRIB_CODENAME
540 ;;
541 esac
542fi
543
544bindhome=
545arch=$(arch)
546
547# Code taken from debootstrap
548if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then
549 arch=`/usr/bin/dpkg --print-architecture`
550elif type udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then
551 arch=`/usr/bin/udpkg --print-architecture`
552else
553 arch=$(arch)
554 if [ "$arch" = "i686" ]; then
555 arch="i386"
556 elif [ "$arch" = "x86_64" ]; then
557 arch="amd64"
558 elif [ "$arch" = "armv7l" ]; then
559 arch="armel"
560 fi
561fi
562
563trim_container=0
564hostarch=$arch
565flushcache=0
566while true
567do
568 case "$1" in
569 -h|--help) usage $0 && exit 0;;
570 -p|--path) path=$2; shift 2;;
571 -n|--name) name=$2; shift 2;;
572 -F|--flush-cache) flushcache=1; shift 1;;
573 -r|--release) release=$2; shift 2;;
574 -b|--bindhome) bindhome=$2; shift 2;;
575 -a|--arch) arch=$2; shift 2;;
576 -x|--trim) trim_container=1; shift 1;;
577 -S|--auth-key) auth_key=$2; shift 2;;
578 --) shift 1; break ;;
579 *) break ;;
580 esac
581done
582
583pwd=`getent passwd $bindhome`
584if [ $? -ne 0 ]; then
585 echo "Error: no password entry found for $bindhome"
586 exit 1
587fi
588
589
590if [ "$arch" == "i686" ]; then
591 arch=i386
592fi
593
594if [ $hostarch = "i386" -a $arch = "amd64" ]; then
595 echo "can't create amd64 container on i386"
596 exit 1
597fi
598
599type debootstrap
600if [ $? -ne 0 ]; then
601 echo "'debootstrap' command is missing"
602 exit 1
603fi
604
605if [ -z "$path" ]; then
606 echo "'path' parameter is required"
607 exit 1
608fi
609
610if [ "$(id -u)" != "0" ]; then
611 echo "This script should be run as 'root'"
612 exit 1
613fi
614
615rootfs=$path/rootfs
616
617install_ubuntu $rootfs $release $flushcache
618if [ $? -ne 0 ]; then
619 echo "failed to install ubuntu $release"
620 exit 1
621fi
622
623configure_ubuntu $rootfs $name $release
624if [ $? -ne 0 ]; then
625 echo "failed to configure ubuntu $release for a container"
626 exit 1
627fi
628
629copy_configuration $path $rootfs $name $arch $release
630if [ $? -ne 0 ]; then
631 echo "failed write configuration file"
632 exit 1
633fi
634
635post_process $rootfs $release $trim_container
636if [ ! -z $bindhome ]; then
637 do_bindhome $rootfs $bindhome
638fi
639
640echo ""
641echo "##"
642echo "# The default user is 'ubuntu' with password 'ubuntu'!"
643echo "# Use the 'sudo' command to run tasks as root in the container."
644echo "##"
645echo ""
0646
=== added directory '.pc/0053-lxc-start-pin-rootfs'
=== renamed directory '.pc/0053-lxc-start-pin-rootfs' => '.pc/0053-lxc-start-pin-rootfs.moved'
=== added file '.pc/0053-lxc-start-pin-rootfs/.timestamp'
=== added directory '.pc/0053-lxc-start-pin-rootfs/src'
=== added directory '.pc/0053-lxc-start-pin-rootfs/src/lxc'
=== added file '.pc/0053-lxc-start-pin-rootfs/src/lxc/conf.c'
--- .pc/0053-lxc-start-pin-rootfs/src/lxc/conf.c 1970-01-01 00:00:00 +0000
+++ .pc/0053-lxc-start-pin-rootfs/src/lxc/conf.c 2012-03-02 15:11:19 +0000
@@ -0,0 +1,1876 @@
1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <dlezcano at fr.ibm.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23#define _GNU_SOURCE
24#include <stdio.h>
25#undef _GNU_SOURCE
26#include <stdlib.h>
27#include <stdarg.h>
28#include <errno.h>
29#include <string.h>
30#include <dirent.h>
31#include <mntent.h>
32#include <unistd.h>
33#include <sys/wait.h>
34#include <pty.h>
35
36#include <linux/loop.h>
37
38#include <sys/types.h>
39#include <sys/utsname.h>
40#include <sys/param.h>
41#include <sys/stat.h>
42#include <sys/socket.h>
43#include <sys/mount.h>
44#include <sys/mman.h>
45#include <sys/prctl.h>
46#include <sys/capability.h>
47#include <sys/personality.h>
48
49#include <arpa/inet.h>
50#include <fcntl.h>
51#include <netinet/in.h>
52#include <net/if.h>
53#include <libgen.h>
54
55#include "network.h"
56#include "error.h"
57#include "parse.h"
58#include "config.h"
59#include "utils.h"
60#include "conf.h"
61#include "log.h"
62#include "lxc.h" /* for lxc_cgroup_set() */
63
64lxc_log_define(lxc_conf, lxc);
65
66#define MAXHWLEN 18
67#define MAXINDEXLEN 20
68#define MAXMTULEN 16
69#define MAXLINELEN 128
70
71#ifndef MS_DIRSYNC
72#define MS_DIRSYNC 128
73#endif
74
75#ifndef MS_REC
76#define MS_REC 16384
77#endif
78
79#ifndef MNT_DETACH
80#define MNT_DETACH 2
81#endif
82
83#ifndef MS_RELATIME
84#define MS_RELATIME (1 << 21)
85#endif
86
87#ifndef MS_STRICTATIME
88#define MS_STRICTATIME (1 << 24)
89#endif
90
91#ifndef CAP_SETFCAP
92#define CAP_SETFCAP 31
93#endif
94
95#ifndef CAP_MAC_OVERRIDE
96#define CAP_MAC_OVERRIDE 32
97#endif
98
99#ifndef CAP_MAC_ADMIN
100#define CAP_MAC_ADMIN 33
101#endif
102
103#ifndef PR_CAPBSET_DROP
104#define PR_CAPBSET_DROP 24
105#endif
106
107extern int pivot_root(const char * new_root, const char * put_old);
108
109typedef int (*instanciate_cb)(struct lxc_handler *, struct lxc_netdev *);
110
111struct mount_opt {
112 char *name;
113 int clear;
114 int flag;
115};
116
117struct caps_opt {
118 char *name;
119 int value;
120};
121
122static int instanciate_veth(struct lxc_handler *, struct lxc_netdev *);
123static int instanciate_macvlan(struct lxc_handler *, struct lxc_netdev *);
124static int instanciate_vlan(struct lxc_handler *, struct lxc_netdev *);
125static int instanciate_phys(struct lxc_handler *, struct lxc_netdev *);
126static int instanciate_empty(struct lxc_handler *, struct lxc_netdev *);
127
128static instanciate_cb netdev_conf[LXC_NET_MAXCONFTYPE + 1] = {
129 [LXC_NET_VETH] = instanciate_veth,
130 [LXC_NET_MACVLAN] = instanciate_macvlan,
131 [LXC_NET_VLAN] = instanciate_vlan,
132 [LXC_NET_PHYS] = instanciate_phys,
133 [LXC_NET_EMPTY] = instanciate_empty,
134};
135
136static struct mount_opt mount_opt[] = {
137 { "defaults", 0, 0 },
138 { "ro", 0, MS_RDONLY },
139 { "rw", 1, MS_RDONLY },
140 { "suid", 1, MS_NOSUID },
141 { "nosuid", 0, MS_NOSUID },
142 { "dev", 1, MS_NODEV },
143 { "nodev", 0, MS_NODEV },
144 { "exec", 1, MS_NOEXEC },
145 { "noexec", 0, MS_NOEXEC },
146 { "sync", 0, MS_SYNCHRONOUS },
147 { "async", 1, MS_SYNCHRONOUS },
148 { "dirsync", 0, MS_DIRSYNC },
149 { "remount", 0, MS_REMOUNT },
150 { "mand", 0, MS_MANDLOCK },
151 { "nomand", 1, MS_MANDLOCK },
152 { "atime", 1, MS_NOATIME },
153 { "noatime", 0, MS_NOATIME },
154 { "diratime", 1, MS_NODIRATIME },
155 { "nodiratime", 0, MS_NODIRATIME },
156 { "bind", 0, MS_BIND },
157 { "rbind", 0, MS_BIND|MS_REC },
158 { "relatime", 0, MS_RELATIME },
159 { "norelatime", 1, MS_RELATIME },
160 { "strictatime", 0, MS_STRICTATIME },
161 { "nostrictatime", 1, MS_STRICTATIME },
162 { NULL, 0, 0 },
163};
164
165static struct caps_opt caps_opt[] = {
166 { "chown", CAP_CHOWN },
167 { "dac_override", CAP_DAC_OVERRIDE },
168 { "dac_read_search", CAP_DAC_READ_SEARCH },
169 { "fowner", CAP_FOWNER },
170 { "fsetid", CAP_FSETID },
171 { "kill", CAP_KILL },
172 { "setgid", CAP_SETGID },
173 { "setuid", CAP_SETUID },
174 { "setpcap", CAP_SETPCAP },
175 { "linux_immutable", CAP_LINUX_IMMUTABLE },
176 { "net_bind_service", CAP_NET_BIND_SERVICE },
177 { "net_broadcast", CAP_NET_BROADCAST },
178 { "net_admin", CAP_NET_ADMIN },
179 { "net_raw", CAP_NET_RAW },
180 { "ipc_lock", CAP_IPC_LOCK },
181 { "ipc_owner", CAP_IPC_OWNER },
182 { "sys_module", CAP_SYS_MODULE },
183 { "sys_rawio", CAP_SYS_RAWIO },
184 { "sys_chroot", CAP_SYS_CHROOT },
185 { "sys_ptrace", CAP_SYS_PTRACE },
186 { "sys_pacct", CAP_SYS_PACCT },
187 { "sys_admin", CAP_SYS_ADMIN },
188 { "sys_boot", CAP_SYS_BOOT },
189 { "sys_nice", CAP_SYS_NICE },
190 { "sys_resource", CAP_SYS_RESOURCE },
191 { "sys_time", CAP_SYS_TIME },
192 { "sys_tty_config", CAP_SYS_TTY_CONFIG },
193 { "mknod", CAP_MKNOD },
194 { "lease", CAP_LEASE },
195#ifdef CAP_AUDIT_WRITE
196 { "audit_write", CAP_AUDIT_WRITE },
197#endif
198#ifdef CAP_AUDIT_CONTROL
199 { "audit_control", CAP_AUDIT_CONTROL },
200#endif
201 { "setfcap", CAP_SETFCAP },
202 { "mac_override", CAP_MAC_OVERRIDE },
203 { "mac_admin", CAP_MAC_ADMIN },
204};
205
206static int run_script(const char *name, const char *section,
207 const char *script, ...)
208{
209 int ret;
210 FILE *f;
211 char *buffer, *p, *output;
212 size_t size = 0;
213 va_list ap;
214
215 INFO("Executing script '%s' for container '%s', config section '%s'",
216 script, name, section);
217
218 va_start(ap, script);
219 while ((p = va_arg(ap, char *)))
220 size += strlen(p) + 1;
221 va_end(ap);
222
223 size += strlen(script);
224 size += strlen(name);
225 size += strlen(section);
226 size += 3;
227
228 if (size > INT_MAX)
229 return -1;
230
231 buffer = alloca(size);
232 if (!buffer) {
233 ERROR("failed to allocate memory");
234 return -1;
235 }
236
237 ret = sprintf(buffer, "%s %s %s", script, name, section);
238
239 va_start(ap, script);
240 while ((p = va_arg(ap, char *)))
241 ret += sprintf(buffer + ret, " %s", p);
242 va_end(ap);
243
244 f = popen(buffer, "r");
245 if (!f) {
246 SYSERROR("popen failed");
247 return -1;
248 }
249
250 output = malloc(LXC_LOG_BUFFER_SIZE);
251 if (!output) {
252 ERROR("failed to allocate memory for script output");
253 return -1;
254 }
255
256 while(fgets(output, LXC_LOG_BUFFER_SIZE, f))
257 DEBUG("script output: %s", output);
258
259 free(output);
260
261 if (pclose(f)) {
262 ERROR("Script exited on error");
263 return -1;
264 }
265
266 return 0;
267}
268
269static int find_fstype_cb(char* buffer, void *data)
270{
271 struct cbarg {
272 const char *rootfs;
273 const char *target;
274 int mntopt;
275 } *cbarg = data;
276
277 char *fstype;
278
279 /* we don't try 'nodev' entries */
280 if (strstr(buffer, "nodev"))
281 return 0;
282
283 fstype = buffer;
284 fstype += lxc_char_left_gc(fstype, strlen(fstype));
285 fstype[lxc_char_right_gc(fstype, strlen(fstype))] = '\0';
286
287 DEBUG("trying to mount '%s'->'%s' with fstype '%s'",
288 cbarg->rootfs, cbarg->target, fstype);
289
290 if (mount(cbarg->rootfs, cbarg->target, fstype, cbarg->mntopt, NULL)) {
291 DEBUG("mount failed with error: %s", strerror(errno));
292 return 0;
293 }
294
295 INFO("mounted '%s' on '%s', with fstype '%s'",
296 cbarg->rootfs, cbarg->target, fstype);
297
298 return 1;
299}
300
301static int mount_unknow_fs(const char *rootfs, const char *target, int mntopt)
302{
303 int i;
304
305 struct cbarg {
306 const char *rootfs;
307 const char *target;
308 int mntopt;
309 } cbarg = {
310 .rootfs = rootfs,
311 .target = target,
312 .mntopt = mntopt,
313 };
314
315 /*
316 * find the filesystem type with brute force:
317 * first we check with /etc/filesystems, in case the modules
318 * are auto-loaded and fall back to the supported kernel fs
319 */
320 char *fsfile[] = {
321 "/etc/filesystems",
322 "/proc/filesystems",
323 };
324
325 for (i = 0; i < sizeof(fsfile)/sizeof(fsfile[0]); i++) {
326
327 int ret;
328
329 if (access(fsfile[i], F_OK))
330 continue;
331
332 ret = lxc_file_for_each_line(fsfile[i], find_fstype_cb, &cbarg);
333 if (ret < 0) {
334 ERROR("failed to parse '%s'", fsfile[i]);
335 return -1;
336 }
337
338 if (ret)
339 return 0;
340 }
341
342 ERROR("failed to determine fs type for '%s'", rootfs);
343 return -1;
344}
345
346static int mount_rootfs_dir(const char *rootfs, const char *target)
347{
348 return mount(rootfs, target, "none", MS_BIND | MS_REC, NULL);
349}
350
351static int setup_lodev(const char *rootfs, int fd, struct loop_info64 *loinfo)
352{
353 int rfd;
354 int ret = -1;
355
356 rfd = open(rootfs, O_RDWR);
357 if (rfd < 0) {
358 SYSERROR("failed to open '%s'", rootfs);
359 return -1;
360 }
361
362 memset(loinfo, 0, sizeof(*loinfo));
363
364 loinfo->lo_flags = LO_FLAGS_AUTOCLEAR;
365
366 if (ioctl(fd, LOOP_SET_FD, rfd)) {
367 SYSERROR("failed to LOOP_SET_FD");
368 goto out;
369 }
370
371 if (ioctl(fd, LOOP_SET_STATUS64, loinfo)) {
372 SYSERROR("failed to LOOP_SET_STATUS64");
373 goto out;
374 }
375
376 ret = 0;
377out:
378 close(rfd);
379
380 return ret;
381}
382
383static int mount_rootfs_file(const char *rootfs, const char *target)
384{
385 struct dirent dirent, *direntp;
386 struct loop_info64 loinfo;
387 int ret = -1, fd = -1;
388 DIR *dir;
389 char path[MAXPATHLEN];
390
391 dir = opendir("/dev");
392 if (!dir) {
393 SYSERROR("failed to open '/dev'");
394 return -1;
395 }
396
397 while (!readdir_r(dir, &dirent, &direntp)) {
398
399 if (!direntp)
400 break;
401
402 if (!strcmp(direntp->d_name, "."))
403 continue;
404
405 if (!strcmp(direntp->d_name, ".."))
406 continue;
407
408 if (strncmp(direntp->d_name, "loop", 4))
409 continue;
410
411 sprintf(path, "/dev/%s", direntp->d_name);
412 fd = open(path, O_RDWR);
413 if (fd < 0)
414 continue;
415
416 if (ioctl(fd, LOOP_GET_STATUS64, &loinfo) == 0) {
417 close(fd);
418 continue;
419 }
420
421 if (errno != ENXIO) {
422 WARN("unexpected error for ioctl on '%s': %m",
423 direntp->d_name);
424 continue;
425 }
426
427 DEBUG("found '%s' free lodev", path);
428
429 ret = setup_lodev(rootfs, fd, &loinfo);
430 if (!ret)
431 ret = mount_unknow_fs(path, target, 0);
432 close(fd);
433
434 break;
435 }
436
437 if (closedir(dir))
438 WARN("failed to close directory");
439
440 return ret;
441}
442
443static int mount_rootfs_block(const char *rootfs, const char *target)
444{
445 return mount_unknow_fs(rootfs, target, 0);
446}
447
448static int mount_rootfs(const char *rootfs, const char *target)
449{
450 char absrootfs[MAXPATHLEN];
451 struct stat s;
452 int i;
453
454 typedef int (*rootfs_cb)(const char *, const char *);
455
456 struct rootfs_type {
457 int type;
458 rootfs_cb cb;
459 } rtfs_type[] = {
460 { S_IFDIR, mount_rootfs_dir },
461 { S_IFBLK, mount_rootfs_block },
462 { S_IFREG, mount_rootfs_file },
463 };
464
465 if (!realpath(rootfs, absrootfs)) {
466 SYSERROR("failed to get real path for '%s'", rootfs);
467 return -1;
468 }
469
470 if (access(absrootfs, F_OK)) {
471 SYSERROR("'%s' is not accessible", absrootfs);
472 return -1;
473 }
474
475 if (stat(absrootfs, &s)) {
476 SYSERROR("failed to stat '%s'", absrootfs);
477 return -1;
478 }
479
480 for (i = 0; i < sizeof(rtfs_type)/sizeof(rtfs_type[0]); i++) {
481
482 if (!__S_ISTYPE(s.st_mode, rtfs_type[i].type))
483 continue;
484
485 return rtfs_type[i].cb(absrootfs, target);
486 }
487
488 ERROR("unsupported rootfs type for '%s'", absrootfs);
489 return -1;
490}
491
492static int setup_utsname(struct utsname *utsname)
493{
494 if (!utsname)
495 return 0;
496
497 if (sethostname(utsname->nodename, strlen(utsname->nodename))) {
498 SYSERROR("failed to set the hostname to '%s'", utsname->nodename);
499 return -1;
500 }
501
502 INFO("'%s' hostname has been setup", utsname->nodename);
503
504 return 0;
505}
506
507static int setup_tty(const struct lxc_rootfs *rootfs,
508 const struct lxc_tty_info *tty_info, char *ttydir)
509{
510 char path[MAXPATHLEN], lxcpath[MAXPATHLEN];
511 int i, ret;
512
513 if (!rootfs->path)
514 return 0;
515
516 for (i = 0; i < tty_info->nbtty; i++) {
517
518 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
519
520 ret = snprintf(path, sizeof(path), "%s/dev/tty%d",
521 rootfs->mount, i + 1);
522 if (ret >= sizeof(path)) {
523 ERROR("pathname too long for ttys");
524 return -1;
525 }
526 if (ttydir) {
527 /* create dev/lxc/tty%d" */
528 snprintf(lxcpath, sizeof(lxcpath), "%s/dev/%s/tty%d",
529 rootfs->mount, ttydir, i + 1);
530 if (ret >= sizeof(lxcpath)) {
531 ERROR("pathname too long for ttys");
532 return -1;
533 }
534 ret = creat(lxcpath, 0660);
535 if (ret==-1 && errno != EEXIST) {
536 SYSERROR("error creating %s\n", lxcpath);
537 return -1;
538 }
539 close(ret);
540 ret = unlink(path);
541 if (ret && errno != ENOENT) {
542 SYSERROR("error unlinking %s\n", path);
543 return -1;
544 }
545
546 if (mount(pty_info->name, lxcpath, "none", MS_BIND, 0)) {
547 WARN("failed to mount '%s'->'%s'",
548 pty_info->name, path);
549 continue;
550 }
551
552 snprintf(lxcpath, sizeof(lxcpath), "%s/tty%d", ttydir, i+1);
553 ret = symlink(lxcpath, path);
554 if (ret) {
555 SYSERROR("failed to create symlink for tty %d\n", i+1);
556 return -1;
557 }
558 } else {
559 if (mount(pty_info->name, path, "none", MS_BIND, 0)) {
560 WARN("failed to mount '%s'->'%s'",
561 pty_info->name, path);
562 continue;
563 }
564 }
565 }
566
567 INFO("%d tty(s) has been setup", tty_info->nbtty);
568
569 return 0;
570}
571
572static int setup_rootfs_pivot_root_cb(char *buffer, void *data)
573{
574 struct lxc_list *mountlist, *listentry, *iterator;
575 char *pivotdir, *mountpoint, *mountentry;
576 int found;
577 void **cbparm;
578
579 mountentry = buffer;
580 cbparm = (void **)data;
581
582 mountlist = cbparm[0];
583 pivotdir = cbparm[1];
584
585 /* parse entry, first field is mountname, ignore */
586 mountpoint = strtok(mountentry, " ");
587 if (!mountpoint)
588 return -1;
589
590 /* second field is mountpoint */
591 mountpoint = strtok(NULL, " ");
592 if (!mountpoint)
593 return -1;
594
595 /* only consider mountpoints below old root fs */
596 if (strncmp(mountpoint, pivotdir, strlen(pivotdir)))
597 return 0;
598
599 /* filter duplicate mountpoints */
600 found = 0;
601 lxc_list_for_each(iterator, mountlist) {
602 if (!strcmp(iterator->elem, mountpoint)) {
603 found = 1;
604 break;
605 }
606 }
607 if (found)
608 return 0;
609
610 /* add entry to list */
611 listentry = malloc(sizeof(*listentry));
612 if (!listentry) {
613 SYSERROR("malloc for mountpoint listentry failed");
614 return -1;
615 }
616
617 listentry->elem = strdup(mountpoint);
618 if (!listentry->elem) {
619 SYSERROR("strdup failed");
620 return -1;
621 }
622 lxc_list_add_tail(mountlist, listentry);
623
624 return 0;
625}
626
627static int umount_oldrootfs(const char *oldrootfs)
628{
629 char path[MAXPATHLEN];
630 void *cbparm[2];
631 struct lxc_list mountlist, *iterator;
632 int ok, still_mounted, last_still_mounted;
633
634 /* read and parse /proc/mounts in old root fs */
635 lxc_list_init(&mountlist);
636
637 /* oldrootfs is on the top tree directory now */
638 snprintf(path, sizeof(path), "/%s", oldrootfs);
639 cbparm[0] = &mountlist;
640
641 cbparm[1] = strdup(path);
642 if (!cbparm[1]) {
643 SYSERROR("strdup failed");
644 return -1;
645 }
646
647 snprintf(path, sizeof(path), "%s/proc/mounts", oldrootfs);
648
649 ok = lxc_file_for_each_line(path,
650 setup_rootfs_pivot_root_cb, &cbparm);
651 if (ok < 0) {
652 SYSERROR("failed to read or parse mount list '%s'", path);
653 return -1;
654 }
655
656 /* umount filesystems until none left or list no longer shrinks */
657 still_mounted = 0;
658 do {
659 last_still_mounted = still_mounted;
660 still_mounted = 0;
661
662 lxc_list_for_each(iterator, &mountlist) {
663
664 /* umount normally */
665 if (!umount(iterator->elem)) {
666 DEBUG("umounted '%s'", (char *)iterator->elem);
667 lxc_list_del(iterator);
668 continue;
669 }
670
671 still_mounted++;
672 }
673
674 } while (still_mounted > 0 && still_mounted != last_still_mounted);
675
676
677 lxc_list_for_each(iterator, &mountlist) {
678
679 /* let's try a lazy umount */
680 if (!umount2(iterator->elem, MNT_DETACH)) {
681 INFO("lazy unmount of '%s'", (char *)iterator->elem);
682 continue;
683 }
684
685 /* be more brutal (nfs) */
686 if (!umount2(iterator->elem, MNT_FORCE)) {
687 INFO("forced unmount of '%s'", (char *)iterator->elem);
688 continue;
689 }
690
691 WARN("failed to unmount '%s'", (char *)iterator->elem);
692 }
693
694 return 0;
695}
696
697static int setup_rootfs_pivot_root(const char *rootfs, const char *pivotdir)
698{
699 char path[MAXPATHLEN];
700 int remove_pivotdir = 0;
701
702 /* change into new root fs */
703 if (chdir(rootfs)) {
704 SYSERROR("can't chdir to new rootfs '%s'", rootfs);
705 return -1;
706 }
707
708 if (!pivotdir)
709 pivotdir = "mnt";
710
711 /* compute the full path to pivotdir under rootfs */
712 snprintf(path, sizeof(path), "%s/%s", rootfs, pivotdir);
713
714 if (access(path, F_OK)) {
715
716 if (mkdir_p(path, 0755)) {
717 SYSERROR("failed to create pivotdir '%s'", path);
718 return -1;
719 }
720
721 remove_pivotdir = 1;
722 DEBUG("created '%s' directory", path);
723 }
724
725 DEBUG("mountpoint for old rootfs is '%s'", path);
726
727 /* pivot_root into our new root fs */
728 if (pivot_root(".", path)) {
729 SYSERROR("pivot_root syscall failed");
730 return -1;
731 }
732
733 if (chdir("/")) {
734 SYSERROR("can't chdir to / after pivot_root");
735 return -1;
736 }
737
738 DEBUG("pivot_root syscall to '%s' successful", rootfs);
739
740 /* we switch from absolute path to relative path */
741 if (umount_oldrootfs(pivotdir))
742 return -1;
743
744 /* remove temporary mount point, we don't consider the removing
745 * as fatal */
746 if (remove_pivotdir && rmdir(pivotdir))
747 WARN("can't remove mountpoint '%s': %m", pivotdir);
748
749 return 0;
750}
751
752static int setup_rootfs(const struct lxc_rootfs *rootfs)
753{
754 if (!rootfs->path)
755 return 0;
756
757 if (access(rootfs->mount, F_OK)) {
758 SYSERROR("failed to access to '%s', check it is present",
759 rootfs->mount);
760 return -1;
761 }
762
763 if (mount_rootfs(rootfs->path, rootfs->mount)) {
764 ERROR("failed to mount rootfs");
765 return -1;
766 }
767
768 DEBUG("mounted '%s' on '%s'", rootfs->path, rootfs->mount);
769
770 return 0;
771}
772
773int setup_pivot_root(const struct lxc_rootfs *rootfs)
774{
775 if (!rootfs->path)
776 return 0;
777
778 if (setup_rootfs_pivot_root(rootfs->mount, rootfs->pivot)) {
779 ERROR("failed to setup pivot root");
780 return -1;
781 }
782
783 return 0;
784}
785
786static int setup_pts(int pts)
787{
788 char target[PATH_MAX];
789
790 if (!pts)
791 return 0;
792
793 if (!access("/dev/pts/ptmx", F_OK) && umount("/dev/pts")) {
794 SYSERROR("failed to umount 'dev/pts'");
795 return -1;
796 }
797
798 if (mount("devpts", "/dev/pts", "devpts", MS_MGC_VAL,
799 "newinstance,ptmxmode=0666")) {
800 SYSERROR("failed to mount a new instance of '/dev/pts'");
801 return -1;
802 }
803
804 if (access("/dev/ptmx", F_OK)) {
805 if (!symlink("/dev/pts/ptmx", "/dev/ptmx"))
806 goto out;
807 SYSERROR("failed to symlink '/dev/pts/ptmx'->'/dev/ptmx'");
808 return -1;
809 }
810
811 if (realpath("/dev/ptmx", target) && !strcmp(target, "/dev/pts/ptmx"))
812 goto out;
813
814 /* fallback here, /dev/pts/ptmx exists just mount bind */
815 if (mount("/dev/pts/ptmx", "/dev/ptmx", "none", MS_BIND, 0)) {
816 SYSERROR("mount failed '/dev/pts/ptmx'->'/dev/ptmx'");
817 return -1;
818 }
819
820 INFO("created new pts instance");
821
822out:
823 return 0;
824}
825
826static int setup_personality(int persona)
827{
828 if (persona == -1)
829 return 0;
830
831 if (personality(persona) < 0) {
832 SYSERROR("failed to set personality to '0x%x'", persona);
833 return -1;
834 }
835
836 INFO("set personality to '0x%x'", persona);
837
838 return 0;
839}
840
841static int setup_dev_console(const struct lxc_rootfs *rootfs,
842 const struct lxc_console *console)
843{
844 char path[MAXPATHLEN];
845 struct stat s;
846 int ret;
847
848 ret = snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
849 if (ret >= sizeof(path)) {
850 ERROR("console path too long\n");
851 return -1;
852 }
853
854 if (access(path, F_OK)) {
855 WARN("rootfs specified but no console found at '%s'", path);
856 return 0;
857 }
858
859 if (console->peer == -1) {
860 INFO("no console output required");
861 return 0;
862 }
863
864 if (stat(path, &s)) {
865 SYSERROR("failed to stat '%s'", path);
866 return -1;
867 }
868
869 if (chmod(console->name, s.st_mode)) {
870 SYSERROR("failed to set mode '0%o' to '%s'",
871 s.st_mode, console->name);
872 return -1;
873 }
874
875 if (mount(console->name, path, "none", MS_BIND, 0)) {
876 ERROR("failed to mount '%s' on '%s'", console->name, path);
877 return -1;
878 }
879
880 INFO("console has been setup");
881 return 0;
882}
883
884static int setup_ttydir_console(const struct lxc_rootfs *rootfs,
885 const struct lxc_console *console,
886 char *ttydir)
887{
888 char path[MAXPATHLEN], lxcpath[MAXPATHLEN];
889 int ret;
890
891 /* create rootfs/dev/<ttydir> directory */
892 ret = snprintf(path, sizeof(path), "%s/dev/%s", rootfs->mount,
893 ttydir);
894 if (ret >= sizeof(path))
895 return -1;
896 ret = mkdir(path, 0755);
897 if (ret && errno != EEXIST) {
898 SYSERROR("failed with errno %d to create %s\n", errno, path);
899 return -1;
900 }
901 INFO("created %s\n", path);
902
903 ret = snprintf(lxcpath, sizeof(lxcpath), "%s/dev/%s/console",
904 rootfs->mount, ttydir);
905 if (ret >= sizeof(lxcpath)) {
906 ERROR("console path too long\n");
907 return -1;
908 }
909
910 snprintf(path, sizeof(path), "%s/dev/console", rootfs->mount);
911 ret = unlink(path);
912 if (ret && errno != ENOENT) {
913 SYSERROR("error unlinking %s\n", path);
914 return -1;
915 }
916
917 ret = creat(lxcpath, 0660);
918 if (ret==-1 && errno != EEXIST) {
919 SYSERROR("error %d creating %s\n", errno, lxcpath);
920 return -1;
921 }
922 close(ret);
923
924 if (console->peer == -1) {
925 INFO("no console output required");
926 return 0;
927 }
928
929 if (mount(console->name, lxcpath, "none", MS_BIND, 0)) {
930 ERROR("failed to mount '%s' on '%s'", console->name, lxcpath);
931 return -1;
932 }
933
934 /* create symlink from rootfs/dev/console to 'lxc/console' */
935 snprintf(lxcpath, sizeof(lxcpath), "%s/console", ttydir);
936 ret = symlink(lxcpath, path);
937 if (ret) {
938 SYSERROR("failed to create symlink for console");
939 return -1;
940 }
941
942 INFO("console has been setup on %s", lxcpath);
943
944 return 0;
945}
946
947static int setup_console(const struct lxc_rootfs *rootfs,
948 const struct lxc_console *console,
949 char *ttydir)
950{
951 /* We don't have a rootfs, /dev/console will be shared */
952 if (!rootfs->path)
953 return 0;
954 if (!ttydir)
955 return setup_dev_console(rootfs, console);
956
957 return setup_ttydir_console(rootfs, console, ttydir);
958}
959
960static int setup_cgroup(const char *name, struct lxc_list *cgroups)
961{
962 struct lxc_list *iterator;
963 struct lxc_cgroup *cg;
964 int ret = -1;
965
966 if (lxc_list_empty(cgroups))
967 return 0;
968
969 lxc_list_for_each(iterator, cgroups) {
970
971 cg = iterator->elem;
972
973 if (lxc_cgroup_set(name, cg->subsystem, cg->value))
974 goto out;
975
976 DEBUG("cgroup '%s' set to '%s'", cg->subsystem, cg->value);
977 }
978
979 ret = 0;
980 INFO("cgroup has been setup");
981out:
982 return ret;
983}
984
985static void parse_mntopt(char *opt, unsigned long *flags, char **data)
986{
987 struct mount_opt *mo;
988
989 /* If opt is found in mount_opt, set or clear flags.
990 * Otherwise append it to data. */
991
992 for (mo = &mount_opt[0]; mo->name != NULL; mo++) {
993 if (!strncmp(opt, mo->name, strlen(mo->name))) {
994 if (mo->clear)
995 *flags &= ~mo->flag;
996 else
997 *flags |= mo->flag;
998 return;
999 }
1000 }
1001
1002 if (strlen(*data))
1003 strcat(*data, ",");
1004 strcat(*data, opt);
1005}
1006
1007static int parse_mntopts(const char *mntopts, unsigned long *mntflags,
1008 char **mntdata)
1009{
1010 char *s, *data;
1011 char *p, *saveptr = NULL;
1012
1013 *mntdata = NULL;
1014 *mntflags = 0L;
1015
1016 if (!mntopts)
1017 return 0;
1018
1019 s = strdup(mntopts);
1020 if (!s) {
1021 SYSERROR("failed to allocate memory");
1022 return -1;
1023 }
1024
1025 data = malloc(strlen(s) + 1);
1026 if (!data) {
1027 SYSERROR("failed to allocate memory");
1028 free(s);
1029 return -1;
1030 }
1031 *data = 0;
1032
1033 for (p = strtok_r(s, ",", &saveptr); p != NULL;
1034 p = strtok_r(NULL, ",", &saveptr))
1035 parse_mntopt(p, mntflags, &data);
1036
1037 if (*data)
1038 *mntdata = data;
1039 else
1040 free(data);
1041 free(s);
1042
1043 return 0;
1044}
1045
1046static int mount_entry(const char *fsname, const char *target,
1047 const char *fstype, unsigned long mountflags,
1048 const char *data)
1049{
1050 if (mount(fsname, target, fstype, mountflags & ~MS_REMOUNT, data)) {
1051 SYSERROR("failed to mount '%s' on '%s'", fsname, target);
1052 return -1;
1053 }
1054
1055 if ((mountflags & MS_REMOUNT) || (mountflags & MS_BIND)) {
1056
1057 DEBUG("remounting %s on %s to respect bind or remount options",
1058 fsname, target);
1059
1060 if (mount(fsname, target, fstype,
1061 mountflags | MS_REMOUNT, data)) {
1062 SYSERROR("failed to mount '%s' on '%s'",
1063 fsname, target);
1064 return -1;
1065 }
1066 }
1067
1068 DEBUG("mounted '%s' on '%s', type '%s'", fsname, target, fstype);
1069
1070 return 0;
1071}
1072
1073static inline int mount_entry_on_systemfs(struct mntent *mntent)
1074{
1075 unsigned long mntflags;
1076 char *mntdata;
1077 int ret;
1078
1079 if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
1080 ERROR("failed to parse mount option '%s'", mntent->mnt_opts);
1081 return -1;
1082 }
1083
1084 ret = mount_entry(mntent->mnt_fsname, mntent->mnt_dir,
1085 mntent->mnt_type, mntflags, mntdata);
1086
1087 free(mntdata);
1088
1089 return ret;
1090}
1091
1092static int mount_entry_on_absolute_rootfs(struct mntent *mntent,
1093 const struct lxc_rootfs *rootfs)
1094{
1095 char *aux;
1096 char path[MAXPATHLEN];
1097 unsigned long mntflags;
1098 char *mntdata;
1099 int ret = 0;
1100
1101 if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
1102 ERROR("failed to parse mount option '%s'", mntent->mnt_opts);
1103 return -1;
1104 }
1105
1106 aux = strstr(mntent->mnt_dir, rootfs->path);
1107 if (!aux) {
1108 WARN("ignoring mount point '%s'", mntent->mnt_dir);
1109 goto out;
1110 }
1111
1112 snprintf(path, MAXPATHLEN, "%s/%s", rootfs->mount,
1113 aux + strlen(rootfs->path));
1114
1115 ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type,
1116 mntflags, mntdata);
1117
1118out:
1119 free(mntdata);
1120 return ret;
1121}
1122
1123static int mount_entry_on_relative_rootfs(struct mntent *mntent,
1124 const char *rootfs)
1125{
1126 char path[MAXPATHLEN];
1127 unsigned long mntflags;
1128 char *mntdata;
1129 int ret;
1130
1131 if (parse_mntopts(mntent->mnt_opts, &mntflags, &mntdata) < 0) {
1132 ERROR("failed to parse mount option '%s'", mntent->mnt_opts);
1133 return -1;
1134 }
1135
1136 /* relative to root mount point */
1137 snprintf(path, sizeof(path), "%s/%s", rootfs, mntent->mnt_dir);
1138
1139 ret = mount_entry(mntent->mnt_fsname, path, mntent->mnt_type,
1140 mntflags, mntdata);
1141
1142 free(mntdata);
1143
1144 return ret;
1145}
1146
1147static int mount_file_entries(const struct lxc_rootfs *rootfs, FILE *file)
1148{
1149 struct mntent *mntent;
1150 int ret = -1;
1151
1152 while ((mntent = getmntent(file))) {
1153
1154 if (!rootfs->path) {
1155 if (mount_entry_on_systemfs(mntent))
1156 goto out;
1157 continue;
1158 }
1159
1160 /* We have a separate root, mounts are relative to it */
1161 if (mntent->mnt_dir[0] != '/') {
1162 if (mount_entry_on_relative_rootfs(mntent,
1163 rootfs->mount))
1164 goto out;
1165 continue;
1166 }
1167
1168 if (mount_entry_on_absolute_rootfs(mntent, rootfs))
1169 goto out;
1170 }
1171
1172 ret = 0;
1173
1174 INFO("mount points have been setup");
1175out:
1176 return ret;
1177}
1178
1179static int setup_mount(const struct lxc_rootfs *rootfs, const char *fstab)
1180{
1181 FILE *file;
1182 int ret;
1183
1184 if (!fstab)
1185 return 0;
1186
1187 file = setmntent(fstab, "r");
1188 if (!file) {
1189 SYSERROR("failed to use '%s'", fstab);
1190 return -1;
1191 }
1192
1193 ret = mount_file_entries(rootfs, file);
1194
1195 endmntent(file);
1196 return ret;
1197}
1198
1199static int setup_mount_entries(const struct lxc_rootfs *rootfs, struct lxc_list *mount)
1200{
1201 FILE *file;
1202 struct lxc_list *iterator;
1203 char *mount_entry;
1204 int ret;
1205
1206 file = tmpfile();
1207 if (!file) {
1208 ERROR("tmpfile error: %m");
1209 return -1;
1210 }
1211
1212 lxc_list_for_each(iterator, mount) {
1213 mount_entry = iterator->elem;
1214 fprintf(file, "%s\n", mount_entry);
1215 }
1216
1217 rewind(file);
1218
1219 ret = mount_file_entries(rootfs, file);
1220
1221 fclose(file);
1222 return ret;
1223}
1224
1225static int setup_caps(struct lxc_list *caps)
1226{
1227 struct lxc_list *iterator;
1228 char *drop_entry;
1229 int i, capid;
1230
1231 lxc_list_for_each(iterator, caps) {
1232
1233 drop_entry = iterator->elem;
1234
1235 capid = -1;
1236
1237 for (i = 0; i < sizeof(caps_opt)/sizeof(caps_opt[0]); i++) {
1238
1239 if (strcmp(drop_entry, caps_opt[i].name))
1240 continue;
1241
1242 capid = caps_opt[i].value;
1243 break;
1244 }
1245
1246 if (capid < 0) {
1247 ERROR("unknown capability %s", drop_entry);
1248 return -1;
1249 }
1250
1251 DEBUG("drop capability '%s' (%d)", drop_entry, capid);
1252
1253 if (prctl(PR_CAPBSET_DROP, capid, 0, 0, 0)) {
1254 SYSERROR("failed to remove %s capability", drop_entry);
1255 return -1;
1256 }
1257
1258 }
1259
1260 DEBUG("capabilities has been setup");
1261
1262 return 0;
1263}
1264
1265static int setup_hw_addr(char *hwaddr, const char *ifname)
1266{
1267 struct sockaddr sockaddr;
1268 struct ifreq ifr;
1269 int ret, fd;
1270
1271 ret = lxc_convert_mac(hwaddr, &sockaddr);
1272 if (ret) {
1273 ERROR("mac address '%s' conversion failed : %s",
1274 hwaddr, strerror(-ret));
1275 return -1;
1276 }
1277
1278 memcpy(ifr.ifr_name, ifname, IFNAMSIZ);
1279 memcpy((char *) &ifr.ifr_hwaddr, (char *) &sockaddr, sizeof(sockaddr));
1280
1281 fd = socket(AF_INET, SOCK_DGRAM, 0);
1282 if (fd < 0) {
1283 ERROR("socket failure : %s", strerror(errno));
1284 return -1;
1285 }
1286
1287 ret = ioctl(fd, SIOCSIFHWADDR, &ifr);
1288 close(fd);
1289 if (ret)
1290 ERROR("ioctl failure : %s", strerror(errno));
1291
1292 DEBUG("mac address '%s' on '%s' has been setup", hwaddr, ifname);
1293
1294 return ret;
1295}
1296
1297static int setup_ipv4_addr(struct lxc_list *ip, int ifindex)
1298{
1299 struct lxc_list *iterator;
1300 struct lxc_inetdev *inetdev;
1301 int err;
1302
1303 lxc_list_for_each(iterator, ip) {
1304
1305 inetdev = iterator->elem;
1306
1307 err = lxc_ipv4_addr_add(ifindex, &inetdev->addr,
1308 &inetdev->bcast, inetdev->prefix);
1309 if (err) {
1310 ERROR("failed to setup_ipv4_addr ifindex %d : %s",
1311 ifindex, strerror(-err));
1312 return -1;
1313 }
1314 }
1315
1316 return 0;
1317}
1318
1319static int setup_ipv6_addr(struct lxc_list *ip, int ifindex)
1320{
1321 struct lxc_list *iterator;
1322 struct lxc_inet6dev *inet6dev;
1323 int err;
1324
1325 lxc_list_for_each(iterator, ip) {
1326
1327 inet6dev = iterator->elem;
1328
1329 err = lxc_ipv6_addr_add(ifindex, &inet6dev->addr,
1330 &inet6dev->mcast, &inet6dev->acast,
1331 inet6dev->prefix);
1332 if (err) {
1333 ERROR("failed to setup_ipv6_addr ifindex %d : %s",
1334 ifindex, strerror(-err));
1335 return -1;
1336 }
1337 }
1338
1339 return 0;
1340}
1341
1342static int setup_netdev(struct lxc_netdev *netdev)
1343{
1344 char ifname[IFNAMSIZ];
1345 char *current_ifname = ifname;
1346 int err;
1347
1348 /* empty network namespace */
1349 if (!netdev->ifindex) {
1350 if (netdev->flags & IFF_UP) {
1351 err = lxc_netdev_up("lo");
1352 if (err) {
1353 ERROR("failed to set the loopback up : %s",
1354 strerror(-err));
1355 return -1;
1356 }
1357 }
1358 return 0;
1359 }
1360
1361 /* retrieve the name of the interface */
1362 if (!if_indextoname(netdev->ifindex, current_ifname)) {
1363 ERROR("no interface corresponding to index '%d'",
1364 netdev->ifindex);
1365 return -1;
1366 }
1367
1368 /* default: let the system to choose one interface name */
1369 if (!netdev->name)
1370 netdev->name = netdev->type == LXC_NET_PHYS ?
1371 netdev->link : "eth%d";
1372
1373 /* rename the interface name */
1374 err = lxc_netdev_rename_by_name(ifname, netdev->name);
1375 if (err) {
1376 ERROR("failed to rename %s->%s : %s", ifname, netdev->name,
1377 strerror(-err));
1378 return -1;
1379 }
1380
1381 /* Re-read the name of the interface because its name has changed
1382 * and would be automatically allocated by the system
1383 */
1384 if (!if_indextoname(netdev->ifindex, current_ifname)) {
1385 ERROR("no interface corresponding to index '%d'",
1386 netdev->ifindex);
1387 return -1;
1388 }
1389
1390 /* set a mac address */
1391 if (netdev->hwaddr) {
1392 if (setup_hw_addr(netdev->hwaddr, current_ifname)) {
1393 ERROR("failed to setup hw address for '%s'",
1394 current_ifname);
1395 return -1;
1396 }
1397 }
1398
1399 /* setup ipv4 addresses on the interface */
1400 if (setup_ipv4_addr(&netdev->ipv4, netdev->ifindex)) {
1401 ERROR("failed to setup ip addresses for '%s'",
1402 ifname);
1403 return -1;
1404 }
1405
1406 /* setup ipv6 addresses on the interface */
1407 if (setup_ipv6_addr(&netdev->ipv6, netdev->ifindex)) {
1408 ERROR("failed to setup ipv6 addresses for '%s'",
1409 ifname);
1410 return -1;
1411 }
1412
1413 /* set the network device up */
1414 if (netdev->flags & IFF_UP) {
1415 int err;
1416
1417 err = lxc_netdev_up(current_ifname);
1418 if (err) {
1419 ERROR("failed to set '%s' up : %s", current_ifname,
1420 strerror(-err));
1421 return -1;
1422 }
1423
1424 /* the network is up, make the loopback up too */
1425 err = lxc_netdev_up("lo");
1426 if (err) {
1427 ERROR("failed to set the loopback up : %s",
1428 strerror(-err));
1429 return -1;
1430 }
1431 }
1432
1433 DEBUG("'%s' has been setup", current_ifname);
1434
1435 return 0;
1436}
1437
1438static int setup_network(struct lxc_list *network)
1439{
1440 struct lxc_list *iterator;
1441 struct lxc_netdev *netdev;
1442
1443 lxc_list_for_each(iterator, network) {
1444
1445 netdev = iterator->elem;
1446
1447 if (setup_netdev(netdev)) {
1448 ERROR("failed to setup netdev");
1449 return -1;
1450 }
1451 }
1452
1453 if (!lxc_list_empty(network))
1454 INFO("network has been setup");
1455
1456 return 0;
1457}
1458
1459struct lxc_conf *lxc_conf_init(void)
1460{
1461 struct lxc_conf *new;
1462
1463 new = malloc(sizeof(*new));
1464 if (!new) {
1465 ERROR("lxc_conf_init : %m");
1466 return NULL;
1467 }
1468 memset(new, 0, sizeof(*new));
1469
1470 new->personality = -1;
1471 new->console.path = NULL;
1472 new->console.peer = -1;
1473 new->console.master = -1;
1474 new->console.slave = -1;
1475 new->console.name[0] = '\0';
1476 new->rootfs.mount = LXCROOTFSMOUNT;
1477 lxc_list_init(&new->cgroup);
1478 lxc_list_init(&new->network);
1479 lxc_list_init(&new->mount_list);
1480 lxc_list_init(&new->caps);
1481
1482 return new;
1483}
1484
1485static int instanciate_veth(struct lxc_handler *handler, struct lxc_netdev *netdev)
1486{
1487 char veth1buf[IFNAMSIZ], *veth1;
1488 char veth2buf[IFNAMSIZ], *veth2;
1489 int err;
1490
1491 if (netdev->priv.veth_attr.pair)
1492 veth1 = netdev->priv.veth_attr.pair;
1493 else {
1494 snprintf(veth1buf, sizeof(veth1buf), "vethXXXXXX");
1495 veth1 = mktemp(veth1buf);
1496 }
1497
1498 snprintf(veth2buf, sizeof(veth2buf), "vethXXXXXX");
1499 veth2 = mktemp(veth2buf);
1500
1501 if (!strlen(veth1) || !strlen(veth2)) {
1502 ERROR("failed to allocate a temporary name");
1503 return -1;
1504 }
1505
1506 err = lxc_veth_create(veth1, veth2);
1507 if (err) {
1508 ERROR("failed to create %s-%s : %s", veth1, veth2,
1509 strerror(-err));
1510 return -1;
1511 }
1512
1513 if (netdev->mtu) {
1514 err = lxc_netdev_set_mtu(veth1, atoi(netdev->mtu));
1515 if (!err)
1516 err = lxc_netdev_set_mtu(veth2, atoi(netdev->mtu));
1517 if (err) {
1518 ERROR("failed to set mtu '%s' for %s-%s : %s",
1519 netdev->mtu, veth1, veth2, strerror(-err));
1520 goto out_delete;
1521 }
1522 }
1523
1524 if (netdev->link) {
1525 err = lxc_bridge_attach(netdev->link, veth1);
1526 if (err) {
1527 ERROR("failed to attach '%s' to the bridge '%s' : %s",
1528 veth1, netdev->link, strerror(-err));
1529 goto out_delete;
1530 }
1531 }
1532
1533 netdev->ifindex = if_nametoindex(veth2);
1534 if (!netdev->ifindex) {
1535 ERROR("failed to retrieve the index for %s", veth2);
1536 goto out_delete;
1537 }
1538
1539 err = lxc_netdev_up(veth1);
1540 if (err) {
1541 ERROR("failed to set %s up : %s", veth1, strerror(-err));
1542 goto out_delete;
1543 }
1544
1545 if (netdev->upscript) {
1546 err = run_script(handler->name, "net", netdev->upscript, "up",
1547 "veth", veth1, (char*) NULL);
1548 if (err)
1549 goto out_delete;
1550 }
1551
1552 DEBUG("instanciated veth '%s/%s', index is '%d'",
1553 veth1, veth2, netdev->ifindex);
1554
1555 return 0;
1556
1557out_delete:
1558 lxc_netdev_delete_by_name(veth1);
1559 return -1;
1560}
1561
1562static int instanciate_macvlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
1563{
1564 char peerbuf[IFNAMSIZ], *peer;
1565 int err;
1566
1567 if (!netdev->link) {
1568 ERROR("no link specified for macvlan netdev");
1569 return -1;
1570 }
1571
1572 snprintf(peerbuf, sizeof(peerbuf), "mcXXXXXX");
1573
1574 peer = mktemp(peerbuf);
1575 if (!strlen(peer)) {
1576 ERROR("failed to make a temporary name");
1577 return -1;
1578 }
1579
1580 err = lxc_macvlan_create(netdev->link, peer,
1581 netdev->priv.macvlan_attr.mode);
1582 if (err) {
1583 ERROR("failed to create macvlan interface '%s' on '%s' : %s",
1584 peer, netdev->link, strerror(-err));
1585 return -1;
1586 }
1587
1588 netdev->ifindex = if_nametoindex(peer);
1589 if (!netdev->ifindex) {
1590 ERROR("failed to retrieve the index for %s", peer);
1591 lxc_netdev_delete_by_name(peer);
1592 return -1;
1593 }
1594
1595 if (netdev->upscript) {
1596 err = run_script(handler->name, "net", netdev->upscript, "up",
1597 "macvlan", netdev->link, (char*) NULL);
1598 if (err)
1599 return -1;
1600 }
1601
1602 DEBUG("instanciated macvlan '%s', index is '%d' and mode '%d'",
1603 peer, netdev->ifindex, netdev->priv.macvlan_attr.mode);
1604
1605 return 0;
1606}
1607
1608/* XXX: merge with instanciate_macvlan */
1609static int instanciate_vlan(struct lxc_handler *handler, struct lxc_netdev *netdev)
1610{
1611 char peer[IFNAMSIZ];
1612 int err;
1613
1614 if (!netdev->link) {
1615 ERROR("no link specified for vlan netdev");
1616 return -1;
1617 }
1618
1619 snprintf(peer, sizeof(peer), "vlan%d", netdev->priv.vlan_attr.vid);
1620
1621 err = lxc_vlan_create(netdev->link, peer, netdev->priv.vlan_attr.vid);
1622 if (err) {
1623 ERROR("failed to create vlan interface '%s' on '%s' : %s",
1624 peer, netdev->link, strerror(-err));
1625 return -1;
1626 }
1627
1628 netdev->ifindex = if_nametoindex(peer);
1629 if (!netdev->ifindex) {
1630 ERROR("failed to retrieve the ifindex for %s", peer);
1631 lxc_netdev_delete_by_name(peer);
1632 return -1;
1633 }
1634
1635 DEBUG("instanciated vlan '%s', ifindex is '%d'", " vlan1000",
1636 netdev->ifindex);
1637
1638 return 0;
1639}
1640
1641static int instanciate_phys(struct lxc_handler *handler, struct lxc_netdev *netdev)
1642{
1643 if (!netdev->link) {
1644 ERROR("no link specified for the physical interface");
1645 return -1;
1646 }
1647
1648 netdev->ifindex = if_nametoindex(netdev->link);
1649 if (!netdev->ifindex) {
1650 ERROR("failed to retrieve the index for %s", netdev->link);
1651 return -1;
1652 }
1653
1654 if (netdev->upscript) {
1655 int err;
1656 err = run_script(handler->name, "net", netdev->upscript,
1657 "up", "phys", netdev->link, (char*) NULL);
1658 if (err)
1659 return -1;
1660 }
1661
1662 return 0;
1663}
1664
1665static int instanciate_empty(struct lxc_handler *handler, struct lxc_netdev *netdev)
1666{
1667 netdev->ifindex = 0;
1668 if (netdev->upscript) {
1669 int err;
1670 err = run_script(handler->name, "net", netdev->upscript,
1671 "up", "empty", (char*) NULL);
1672 if (err)
1673 return -1;
1674 }
1675 return 0;
1676}
1677
1678int lxc_create_network(struct lxc_handler *handler)
1679{
1680 struct lxc_list *network = &handler->conf->network;
1681 struct lxc_list *iterator;
1682 struct lxc_netdev *netdev;
1683
1684 lxc_list_for_each(iterator, network) {
1685
1686 netdev = iterator->elem;
1687
1688 if (netdev->type < 0 || netdev->type > LXC_NET_MAXCONFTYPE) {
1689 ERROR("invalid network configuration type '%d'",
1690 netdev->type);
1691 return -1;
1692 }
1693
1694 if (netdev_conf[netdev->type](handler, netdev)) {
1695 ERROR("failed to create netdev");
1696 return -1;
1697 }
1698
1699 }
1700
1701 return 0;
1702}
1703
1704void lxc_delete_network(struct lxc_list *network)
1705{
1706 struct lxc_list *iterator;
1707 struct lxc_netdev *netdev;
1708
1709 lxc_list_for_each(iterator, network) {
1710 netdev = iterator->elem;
1711 if (netdev->ifindex == 0)
1712 continue;
1713
1714 /* Recent kernels already delete the virtual devices */
1715 if (netdev->type != LXC_NET_PHYS)
1716 continue;
1717
1718 if (lxc_netdev_rename_by_index(netdev->ifindex, netdev->link))
1719 WARN("failed to rename to the initial name the netdev '%s'",
1720 netdev->link);
1721 }
1722}
1723
1724int lxc_assign_network(struct lxc_list *network, pid_t pid)
1725{
1726 struct lxc_list *iterator;
1727 struct lxc_netdev *netdev;
1728 int err;
1729
1730 lxc_list_for_each(iterator, network) {
1731
1732 netdev = iterator->elem;
1733
1734 /* empty network namespace, nothing to move */
1735 if (!netdev->ifindex)
1736 continue;
1737
1738 err = lxc_netdev_move_by_index(netdev->ifindex, pid);
1739 if (err) {
1740 ERROR("failed to move '%s' to the container : %s",
1741 netdev->link, strerror(-err));
1742 return -1;
1743 }
1744
1745 DEBUG("move '%s' to '%d'", netdev->name, pid);
1746 }
1747
1748 return 0;
1749}
1750
1751int lxc_create_tty(const char *name, struct lxc_conf *conf)
1752{
1753 struct lxc_tty_info *tty_info = &conf->tty_info;
1754 int i;
1755
1756 /* no tty in the configuration */
1757 if (!conf->tty)
1758 return 0;
1759
1760 tty_info->pty_info =
1761 malloc(sizeof(*tty_info->pty_info)*conf->tty);
1762 if (!tty_info->pty_info) {
1763 SYSERROR("failed to allocate pty_info");
1764 return -1;
1765 }
1766
1767 for (i = 0; i < conf->tty; i++) {
1768
1769 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
1770
1771 if (openpty(&pty_info->master, &pty_info->slave,
1772 pty_info->name, NULL, NULL)) {
1773 SYSERROR("failed to create pty #%d", i);
1774 tty_info->nbtty = i;
1775 lxc_delete_tty(tty_info);
1776 return -1;
1777 }
1778
1779 DEBUG("allocated pty '%s' (%d/%d)",
1780 pty_info->name, pty_info->master, pty_info->slave);
1781
1782 /* Prevent leaking the file descriptors to the container */
1783 fcntl(pty_info->master, F_SETFD, FD_CLOEXEC);
1784 fcntl(pty_info->slave, F_SETFD, FD_CLOEXEC);
1785
1786 pty_info->busy = 0;
1787 }
1788
1789 tty_info->nbtty = conf->tty;
1790
1791 INFO("tty's configured");
1792
1793 return 0;
1794}
1795
1796void lxc_delete_tty(struct lxc_tty_info *tty_info)
1797{
1798 int i;
1799
1800 for (i = 0; i < tty_info->nbtty; i++) {
1801 struct lxc_pty_info *pty_info = &tty_info->pty_info[i];
1802
1803 close(pty_info->master);
1804 close(pty_info->slave);
1805 }
1806
1807 free(tty_info->pty_info);
1808 tty_info->nbtty = 0;
1809}
1810
1811int lxc_setup(const char *name, struct lxc_conf *lxc_conf)
1812{
1813 if (setup_utsname(lxc_conf->utsname)) {
1814 ERROR("failed to setup the utsname for '%s'", name);
1815 return -1;
1816 }
1817
1818 if (setup_network(&lxc_conf->network)) {
1819 ERROR("failed to setup the network for '%s'", name);
1820 return -1;
1821 }
1822
1823 if (setup_rootfs(&lxc_conf->rootfs)) {
1824 ERROR("failed to setup rootfs for '%s'", name);
1825 return -1;
1826 }
1827
1828 if (setup_mount(&lxc_conf->rootfs, lxc_conf->fstab)) {
1829 ERROR("failed to setup the mounts for '%s'", name);
1830 return -1;
1831 }
1832
1833 if (setup_mount_entries(&lxc_conf->rootfs, &lxc_conf->mount_list)) {
1834 ERROR("failed to setup the mount entries for '%s'", name);
1835 return -1;
1836 }
1837
1838 if (setup_cgroup(name, &lxc_conf->cgroup)) {
1839 ERROR("failed to setup the cgroups for '%s'", name);
1840 return -1;
1841 }
1842
1843 if (setup_console(&lxc_conf->rootfs, &lxc_conf->console, lxc_conf->ttydir)) {
1844 ERROR("failed to setup the console for '%s'", name);
1845 return -1;
1846 }
1847
1848 if (setup_tty(&lxc_conf->rootfs, &lxc_conf->tty_info, lxc_conf->ttydir)) {
1849 ERROR("failed to setup the ttys for '%s'", name);
1850 return -1;
1851 }
1852
1853 if (setup_pivot_root(&lxc_conf->rootfs)) {
1854 ERROR("failed to set rootfs for '%s'", name);
1855 return -1;
1856 }
1857
1858 if (setup_pts(lxc_conf->pts)) {
1859 ERROR("failed to setup the new pts instance");
1860 return -1;
1861 }
1862
1863 if (setup_personality(lxc_conf->personality)) {
1864 ERROR("failed to setup personality");
1865 return -1;
1866 }
1867
1868 if (setup_caps(&lxc_conf->caps)) {
1869 ERROR("failed to drop capabilities");
1870 return -1;
1871 }
1872
1873 NOTICE("'%s' is setup.", name);
1874
1875 return 0;
1876}
01877
=== added file '.pc/0053-lxc-start-pin-rootfs/src/lxc/conf.h'
--- .pc/0053-lxc-start-pin-rootfs/src/lxc/conf.h 1970-01-01 00:00:00 +0000
+++ .pc/0053-lxc-start-pin-rootfs/src/lxc/conf.h 2012-03-02 15:11:19 +0000
@@ -0,0 +1,233 @@
1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <dlezcano at fr.ibm.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23#ifndef _conf_h
24#define _conf_h
25
26#include <netinet/in.h>
27#include <sys/param.h>
28
29#include <lxc/list.h>
30
31#include <lxc/start.h> /* for lxc_handler */
32
33enum {
34 LXC_NET_EMPTY,
35 LXC_NET_VETH,
36 LXC_NET_MACVLAN,
37 LXC_NET_PHYS,
38 LXC_NET_VLAN,
39 LXC_NET_MAXCONFTYPE,
40};
41
42/*
43 * Defines the structure to configure an ipv4 address
44 * @address : ipv4 address
45 * @broadcast : ipv4 broadcast address
46 * @mask : network mask
47 */
48struct lxc_inetdev {
49 struct in_addr addr;
50 struct in_addr bcast;
51 int prefix;
52};
53
54struct lxc_route {
55 struct in_addr addr;
56};
57
58/*
59 * Defines the structure to configure an ipv6 address
60 * @flags : set the address up
61 * @address : ipv6 address
62 * @broadcast : ipv6 broadcast address
63 * @mask : network mask
64 */
65struct lxc_inet6dev {
66 struct in6_addr addr;
67 struct in6_addr mcast;
68 struct in6_addr acast;
69 int prefix;
70};
71
72struct lxc_route6 {
73 struct in6_addr addr;
74};
75
76struct ifla_veth {
77 char *pair; /* pair name */
78};
79
80struct ifla_vlan {
81 uint flags;
82 uint fmask;
83 ushort vid;
84 ushort pad;
85};
86
87struct ifla_macvlan {
88 int mode; /* private, vepa, bridge */
89};
90
91union netdev_p {
92 struct ifla_veth veth_attr;
93 struct ifla_vlan vlan_attr;
94 struct ifla_macvlan macvlan_attr;
95};
96
97/*
98 * Defines a structure to configure a network device
99 * @link : lxc.network.link, name of bridge or host iface to attach if any
100 * @name : lxc.network.name, name of iface on the container side
101 * @flags : flag of the network device (IFF_UP, ... )
102 * @ipv4 : a list of ipv4 addresses to be set on the network device
103 * @ipv6 : a list of ipv6 addresses to be set on the network device
104 * @upscript : a script filename to be executed during interface configuration
105 */
106struct lxc_netdev {
107 int type;
108 int flags;
109 int ifindex;
110 char *link;
111 char *name;
112 char *hwaddr;
113 char *mtu;
114 union netdev_p priv;
115 struct lxc_list ipv4;
116 struct lxc_list ipv6;
117 char *upscript;
118};
119
120/*
121 * Defines a generic struct to configure the control group.
122 * It is up to the programmer to specify the right subsystem.
123 * @subsystem : the targetted subsystem
124 * @value : the value to set
125 */
126struct lxc_cgroup {
127 char *subsystem;
128 char *value;
129};
130
131/*
132 * Defines a structure containing a pty information for
133 * virtualizing a tty
134 * @name : the path name of the slave pty side
135 * @master : the file descriptor of the master
136 * @slave : the file descriptor of the slave
137 */
138struct lxc_pty_info {
139 char name[MAXPATHLEN];
140 int master;
141 int slave;
142 int busy;
143};
144
145/*
146 * Defines the number of tty configured and contains the
147 * instanciated ptys
148 * @nbtty = number of configured ttys
149 */
150struct lxc_tty_info {
151 int nbtty;
152 struct lxc_pty_info *pty_info;
153};
154
155/*
156 * Defines the structure to store the console information
157 * @peer : the file descriptor put/get console traffic
158 * @name : the file name of the slave pty
159 */
160struct lxc_console {
161 int slave;
162 int master;
163 int peer;
164 char *path;
165 char name[MAXPATHLEN];
166 struct termios *tios;
167};
168
169/*
170 * Defines a structure to store the rootfs location, the
171 * optionals pivot_root, rootfs mount paths
172 * @rootfs : a path to the rootfs
173 * @pivot_root : a path to a pivot_root location to be used
174 */
175struct lxc_rootfs {
176 char *path;
177 char *mount;
178 char *pivot;
179};
180
181/*
182 * Defines the global container configuration
183 * @rootfs : root directory to run the container
184 * @pivotdir : pivotdir path, if not set default will be used
185 * @mount : list of mount points
186 * @tty : numbers of tty
187 * @pts : new pts instance
188 * @mount_list : list of mount point (alternative to fstab file)
189 * @network : network configuration
190 * @utsname : container utsname
191 * @fstab : path to a fstab file format
192 * @caps : list of the capabilities
193 * @tty_info : tty data
194 * @console : console data
195 * @ttydir : directory (under /dev) in which to create console and ttys
196 */
197struct lxc_conf {
198 char *fstab;
199 int tty;
200 int pts;
201 int reboot;
202 int need_utmp_watch;
203 int personality;
204 struct utsname *utsname;
205 struct lxc_list cgroup;
206 struct lxc_list network;
207 struct lxc_list mount_list;
208 struct lxc_list caps;
209 struct lxc_tty_info tty_info;
210 struct lxc_console console;
211 struct lxc_rootfs rootfs;
212 char *ttydir;
213 int close_all_fds;
214};
215
216/*
217 * Initialize the lxc configuration structure
218 */
219extern struct lxc_conf *lxc_conf_init(void);
220
221extern int lxc_create_network(struct lxc_handler *handler);
222extern void lxc_delete_network(struct lxc_list *networks);
223extern int lxc_assign_network(struct lxc_list *networks, pid_t pid);
224
225extern int lxc_create_tty(const char *name, struct lxc_conf *conf);
226extern void lxc_delete_tty(struct lxc_tty_info *tty_info);
227
228/*
229 * Configure the container from inside
230 */
231
232extern int lxc_setup(const char *name, struct lxc_conf *lxc_conf);
233#endif
0234
=== added file '.pc/0053-lxc-start-pin-rootfs/src/lxc/start.c'
--- .pc/0053-lxc-start-pin-rootfs/src/lxc/start.c 1970-01-01 00:00:00 +0000
+++ .pc/0053-lxc-start-pin-rootfs/src/lxc/start.c 2012-03-02 15:11:19 +0000
@@ -0,0 +1,748 @@
1/*
2 * lxc: linux Container library
3 *
4 * (C) Copyright IBM Corp. 2007, 2008
5 *
6 * Authors:
7 * Daniel Lezcano <dlezcano at fr.ibm.com>
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24#include "../config.h"
25#include <stdio.h>
26#undef _GNU_SOURCE
27#include <string.h>
28#include <stdlib.h>
29#include <dirent.h>
30#include <errno.h>
31#include <unistd.h>
32#include <signal.h>
33#include <fcntl.h>
34#include <termios.h>
35#include <namespace.h>
36#include <sys/param.h>
37#include <sys/file.h>
38#include <sys/mount.h>
39#include <sys/stat.h>
40#include <sys/types.h>
41#include <sys/prctl.h>
42#include <sys/types.h>
43#include <sys/capability.h>
44#include <sys/wait.h>
45#include <sys/un.h>
46#include <sys/poll.h>
47
48#ifdef HAVE_SYS_SIGNALFD_H
49# include <sys/signalfd.h>
50#else
51/* assume kernel headers are too old */
52#include <stdint.h>
53struct signalfd_siginfo
54{
55 uint32_t ssi_signo;
56 int32_t ssi_errno;
57 int32_t ssi_code;
58 uint32_t ssi_pid;
59 uint32_t ssi_uid;
60 int32_t ssi_fd;
61 uint32_t ssi_tid;
62 uint32_t ssi_band;
63 uint32_t ssi_overrun;
64 uint32_t ssi_trapno;
65 int32_t ssi_status;
66 int32_t ssi_int;
67 uint64_t ssi_ptr;
68 uint64_t ssi_utime;
69 uint64_t ssi_stime;
70 uint64_t ssi_addr;
71 uint8_t __pad[48];
72};
73
74# ifndef __NR_signalfd4
75/* assume kernel headers are too old */
76# if __i386__
77# define __NR_signalfd4 327
78# elif __x86_64__
79# define __NR_signalfd4 289
80# elif __powerpc__
81# define __NR_signalfd4 313
82# elif __s390x__
83# define __NR_signalfd4 322
84# endif
85#endif
86
87# ifndef __NR_signalfd
88/* assume kernel headers are too old */
89# if __i386__
90# define __NR_signalfd 321
91# elif __x86_64__
92# define __NR_signalfd 282
93# elif __powerpc__
94# define __NR_signalfd 305
95# elif __s390x__
96# define __NR_signalfd 316
97# endif
98#endif
99
100int signalfd(int fd, const sigset_t *mask, int flags)
101{
102 int retval;
103
104 retval = syscall (__NR_signalfd4, fd, mask, _NSIG / 8, flags);
105 if (errno == ENOSYS && flags == 0)
106 retval = syscall (__NR_signalfd, fd, mask, _NSIG / 8);
107 return retval;
108}
109#endif
110
111#if !HAVE_DECL_PR_CAPBSET_DROP
112#define PR_CAPBSET_DROP 24
113#endif
114
115#include "start.h"
116#include "conf.h"
117#include "log.h"
118#include "cgroup.h"
119#include "error.h"
120#include "af_unix.h"
121#include "mainloop.h"
122#include "utils.h"
123#include "utmp.h"
124#include "monitor.h"
125#include "commands.h"
126#include "console.h"
127#include "sync.h"
128
129lxc_log_define(lxc_start, lxc);
130
131LXC_TTY_HANDLER(SIGINT);
132LXC_TTY_HANDLER(SIGQUIT);
133
134static int match_fd(int fd)
135{
136 return (fd == 0 || fd == 1 || fd == 2);
137}
138
139int lxc_check_inherited(struct lxc_conf *conf, int fd_to_ignore)
140{
141 struct dirent dirent, *direntp;
142 int fd, fddir;
143 DIR *dir;
144 int ret = 0;
145
146restart:
147 dir = opendir("/proc/self/fd");
148 if (!dir) {
149 WARN("failed to open directory: %m");
150 return -1;
151 }
152
153 fddir = dirfd(dir);
154
155 while (!readdir_r(dir, &dirent, &direntp)) {
156 char procpath[64];
157 char path[PATH_MAX];
158 int gotpath = 1;
159
160 if (!direntp)
161 break;
162
163 if (!strcmp(direntp->d_name, "."))
164 continue;
165
166 if (!strcmp(direntp->d_name, ".."))
167 continue;
168
169 fd = atoi(direntp->d_name);
170
171 if (fd == fddir || fd == lxc_log_fd || fd == fd_to_ignore)
172 continue;
173
174 if (match_fd(fd))
175 continue;
176
177 snprintf(procpath, sizeof(procpath), "/proc/self/fd/%d", fd);
178 if (readlink(procpath, path, sizeof(path)) == -1)
179 gotpath = 0;
180
181 /*
182 * found inherited fd
183 */
184
185 if (conf->close_all_fds) {
186 if (!gotpath)
187 INFO("closing inherited fd %d\n", fd);
188 else
189 INFO("closing inherited fd %d (%s)", fd, path);
190 close(fd);
191 closedir(dir);
192 goto restart;
193 }
194
195 ret = -1;
196
197 snprintf(procpath, sizeof(procpath), "/proc/self/fd/%d", fd);
198
199 if (!gotpath)
200 ERROR("readlink(%s) failed : %m", procpath);
201 else
202 ERROR("inherited fd %d on %s", fd, path);
203 }
204
205 if (closedir(dir))
206 ERROR("failed to close directory");
207 return ret;
208}
209
210static int setup_signal_fd(sigset_t *oldmask)
211{
212 sigset_t mask;
213 int fd;
214
215 /* Block everything except serious error signals */
216 if (sigfillset(&mask) ||
217 sigdelset(&mask, SIGILL) ||
218 sigdelset(&mask, SIGSEGV) ||
219 sigdelset(&mask, SIGBUS) ||
220 sigprocmask(SIG_BLOCK, &mask, oldmask)) {
221 SYSERROR("failed to set signal mask");
222 return -1;
223 }
224
225 fd = signalfd(-1, &mask, 0);
226 if (fd < 0) {
227 SYSERROR("failed to create the signal fd");
228 return -1;
229 }
230
231 if (fcntl(fd, F_SETFD, FD_CLOEXEC)) {
232 SYSERROR("failed to set sigfd to close-on-exec");
233 close(fd);
234 return -1;
235 }
236
237 DEBUG("sigchild handler set");
238
239 return fd;
240}
241
242static int signal_handler(int fd, void *data,
243 struct lxc_epoll_descr *descr)
244{
245 struct signalfd_siginfo siginfo;
246 int ret;
247 pid_t *pid = data;
248
249 ret = read(fd, &siginfo, sizeof(siginfo));
250 if (ret < 0) {
251 ERROR("failed to read signal info");
252 return -1;
253 }
254
255 if (ret != sizeof(siginfo)) {
256 ERROR("unexpected siginfo size");
257 return -1;
258 }
259
260 if (siginfo.ssi_signo != SIGCHLD) {
261 kill(*pid, siginfo.ssi_signo);
262 INFO("forwarded signal %d to pid %d", siginfo.ssi_signo, *pid);
263 return 0;
264 }
265
266 if (siginfo.ssi_code == CLD_STOPPED ||
267 siginfo.ssi_code == CLD_CONTINUED) {
268 INFO("container init process was stopped/continued");
269 return 0;
270 }
271
272 /* more robustness, protect ourself from a SIGCHLD sent
273 * by a process different from the container init
274 */
275 if (siginfo.ssi_pid != *pid) {
276 WARN("invalid pid for SIGCHLD");
277 return 0;
278 }
279
280 DEBUG("container init process exited");
281 return 1;
282}
283
284int lxc_pid_callback(int fd, struct lxc_request *request,
285 struct lxc_handler *handler)
286{
287 struct lxc_answer answer;
288 int ret;
289
290 answer.pid = handler->pid;
291 answer.ret = 0;
292
293 ret = send(fd, &answer, sizeof(answer), 0);
294 if (ret < 0) {
295 WARN("failed to send answer to the peer");
296 return -1;
297 }
298
299 if (ret != sizeof(answer)) {
300 ERROR("partial answer sent");
301 return -1;
302 }
303
304 return 0;
305}
306
307int lxc_set_state(const char *name, struct lxc_handler *handler, lxc_state_t state)
308{
309 handler->state = state;
310 lxc_monitor_send_state(name, state);
311 return 0;
312}
313
314int lxc_poll(const char *name, struct lxc_handler *handler)
315{
316 int sigfd = handler->sigfd;
317 int pid = handler->pid;
318 struct lxc_epoll_descr descr;
319
320 if (lxc_mainloop_open(&descr)) {
321 ERROR("failed to create mainloop");
322 goto out_sigfd;
323 }
324
325 if (lxc_mainloop_add_handler(&descr, sigfd, signal_handler, &pid)) {
326 ERROR("failed to add handler for the signal");
327 goto out_mainloop_open;
328 }
329
330 if (lxc_console_mainloop_add(&descr, handler)) {
331 ERROR("failed to add console handler to mainloop");
332 goto out_mainloop_open;
333 }
334
335 if (lxc_command_mainloop_add(name, &descr, handler)) {
336 ERROR("failed to add command handler to mainloop");
337 goto out_mainloop_open;
338 }
339
340 if (handler->conf->need_utmp_watch) {
341 if (lxc_utmp_mainloop_add(&descr, handler)) {
342 ERROR("failed to add utmp handler to mainloop");
343 goto out_mainloop_open;
344 }
345 }
346
347 return lxc_mainloop(&descr);
348
349out_mainloop_open:
350 lxc_mainloop_close(&descr);
351out_sigfd:
352 close(sigfd);
353 return -1;
354}
355
356extern int lxc_caps_check(void);
357
358struct lxc_handler *lxc_init(const char *name, struct lxc_conf *conf)
359{
360 struct lxc_handler *handler;
361
362 if (!lxc_caps_check()) {
363 ERROR("Not running with sufficient privilege");
364 return NULL;
365 }
366
367 handler = malloc(sizeof(*handler));
368 if (!handler)
369 return NULL;
370
371 memset(handler, 0, sizeof(*handler));
372
373 handler->conf = conf;
374
375 handler->name = strdup(name);
376 if (!handler->name) {
377 ERROR("failed to allocate memory");
378 goto out_free;
379 }
380
381 /* Begin the set the state to STARTING*/
382 if (lxc_set_state(name, handler, STARTING)) {
383 ERROR("failed to set state '%s'", lxc_state2str(STARTING));
384 goto out_free_name;
385 }
386
387 if (lxc_create_tty(name, conf)) {
388 ERROR("failed to create the ttys");
389 goto out_aborting;
390 }
391
392 if (lxc_create_console(conf)) {
393 ERROR("failed to create console");
394 goto out_delete_tty;
395 }
396
397 /* the signal fd has to be created before forking otherwise
398 * if the child process exits before we setup the signal fd,
399 * the event will be lost and the command will be stuck */
400 handler->sigfd = setup_signal_fd(&handler->oldmask);
401 if (handler->sigfd < 0) {
402 ERROR("failed to set sigchild fd handler");
403 goto out_delete_console;
404 }
405
406 INFO("'%s' is initialized", name);
407 return handler;
408
409out_delete_console:
410 lxc_delete_console(&conf->console);
411out_delete_tty:
412 lxc_delete_tty(&conf->tty_info);
413out_aborting:
414 lxc_set_state(name, handler, ABORTING);
415out_free_name:
416 free(handler->name);
417 handler->name = NULL;
418out_free:
419 free(handler);
420 return NULL;
421}
422
423void lxc_fini(const char *name, struct lxc_handler *handler)
424{
425 /* The STOPPING state is there for future cleanup code
426 * which can take awhile
427 */
428 lxc_set_state(name, handler, STOPPING);
429 lxc_set_state(name, handler, STOPPED);
430
431 /* reset mask set by setup_signal_fd */
432 if (sigprocmask(SIG_SETMASK, &handler->oldmask, NULL))
433 WARN("failed to restore sigprocmask");
434
435 lxc_delete_console(&handler->conf->console);
436 lxc_delete_tty(&handler->conf->tty_info);
437 free(handler->name);
438 free(handler);
439}
440
441void lxc_abort(const char *name, struct lxc_handler *handler)
442{
443 lxc_set_state(name, handler, ABORTING);
444 if (handler->pid > 0)
445 kill(handler->pid, SIGKILL);
446}
447
448#include <sys/reboot.h>
449#include <linux/reboot.h>
450
451/*
452 * reboot(LINUX_REBOOT_CMD_CAD_ON) will return -EINVAL
453 * in a child pid namespace if container reboot support exists.
454 * Otherwise, it will either succeed or return -EPERM.
455 */
456static int container_reboot_supported(void *arg)
457{
458 int *cmd = arg;
459 int ret;
460
461 ret = reboot(*cmd);
462 if (ret == -1 && errno == EINVAL)
463 return 1;
464 return 0;
465}
466
467static int must_drop_cap_sys_boot(void)
468{
469 FILE *f = fopen("/proc/sys/kernel/ctrl-alt-del", "r");
470 int ret, cmd, v;
471 long stack_size = 4096;
472 void *stack = alloca(stack_size) + stack_size;
473 int status;
474 pid_t pid;
475
476 if (!f) {
477 DEBUG("failed to open /proc/sys/kernel/ctrl-alt-del");
478 return 1;
479 }
480
481 ret = fscanf(f, "%d", &v);
482 fclose(f);
483 if (ret != 1) {
484 DEBUG("Failed to read /proc/sys/kernel/ctrl-alt-del");
485 return 1;
486 }
487 cmd = v ? LINUX_REBOOT_CMD_CAD_ON : LINUX_REBOOT_CMD_CAD_OFF;
488
489 pid = clone(container_reboot_supported, stack, CLONE_NEWPID | SIGCHLD, &cmd);
490 if (pid < 0) {
491 SYSERROR("failed to clone\n");
492 return -1;
493 }
494 if (wait(&status) < 0) {
495 SYSERROR("unexpected wait error: %m\n");
496 return -1;
497 }
498
499 if (WEXITSTATUS(status) != 1)
500 return 1;
501
502 return 0;
503}
504
505static int do_start(void *data)
506{
507 struct lxc_handler *handler = data;
508
509 if (sigprocmask(SIG_SETMASK, &handler->oldmask, NULL)) {
510 SYSERROR("failed to set sigprocmask");
511 return -1;
512 }
513
514 /* This prctl must be before the synchro, so if the parent
515 * dies before we set the parent death signal, we will detect
516 * its death with the synchro right after, otherwise we have
517 * a window where the parent can exit before we set the pdeath
518 * signal leading to a unsupervized container.
519 */
520 if (prctl(PR_SET_PDEATHSIG, SIGKILL, 0, 0, 0)) {
521 SYSERROR("failed to set pdeath signal");
522 return -1;
523 }
524
525 lxc_sync_fini_parent(handler);
526
527 /* Tell the parent task it can begin to configure the
528 * container and wait for it to finish
529 */
530 if (lxc_sync_barrier_parent(handler, LXC_SYNC_CONFIGURE))
531 return -1;
532
533 if (must_drop_cap_sys_boot()) {
534 if (prctl(PR_CAPBSET_DROP, CAP_SYS_BOOT, 0, 0, 0)) {
535 SYSERROR("failed to remove CAP_SYS_BOOT capability");
536 return -1;
537 }
538 handler->conf->need_utmp_watch = 1;
539 DEBUG("Dropped cap_sys_boot\n");
540 } else {
541 DEBUG("Not dropping cap_sys_boot or watching utmp\n");
542 handler->conf->need_utmp_watch = 0;
543 }
544
545 /* Setup the container, ip, names, utsname, ... */
546 if (lxc_setup(handler->name, handler->conf)) {
547 ERROR("failed to setup the container");
548 goto out_warn_father;
549 }
550
551 close(handler->sigfd);
552
553 /* after this call, we are in error because this
554 * ops should not return as it execs */
555 if (handler->ops->start(handler, handler->data))
556 return -1;
557
558out_warn_father:
559 lxc_sync_wake_parent(handler, LXC_SYNC_POST_CONFIGURE);
560 return -1;
561}
562
563int lxc_spawn(struct lxc_handler *handler)
564{
565 int clone_flags;
566 int failed_before_rename = 0;
567 const char *name = handler->name;
568
569 if (lxc_sync_init(handler))
570 return -1;
571
572 clone_flags = CLONE_NEWUTS|CLONE_NEWPID|CLONE_NEWIPC|CLONE_NEWNS;
573 if (!lxc_list_empty(&handler->conf->network)) {
574
575 clone_flags |= CLONE_NEWNET;
576
577 /* that should be done before the clone because we will
578 * fill the netdev index and use them in the child
579 */
580 if (lxc_create_network(handler)) {
581 ERROR("failed to create the network");
582 lxc_sync_fini(handler);
583 return -1;
584 }
585 }
586
587
588 /* Create a process in a new set of namespaces */
589 handler->pid = lxc_clone(do_start, handler, clone_flags);
590 if (handler->pid < 0) {
591 SYSERROR("failed to fork into a new namespace");
592 goto out_delete_net;
593 }
594
595 lxc_sync_fini_child(handler);
596
597 if (lxc_sync_wait_child(handler, LXC_SYNC_CONFIGURE))
598 failed_before_rename = 1;
599
600 if (lxc_cgroup_create(name, handler->pid))
601 goto out_delete_net;
602
603 if (failed_before_rename)
604 goto out_delete_net;
605
606 /* Create the network configuration */
607 if (clone_flags & CLONE_NEWNET) {
608 if (lxc_assign_network(&handler->conf->network, handler->pid)) {
609 ERROR("failed to create the configured network");
610 goto out_delete_net;
611 }
612 }
613
614 /* Tell the child to continue its initialization and wait for
615 * it to exec or return an error
616 */
617 if (lxc_sync_barrier_child(handler, LXC_SYNC_POST_CONFIGURE))
618 return -1;
619
620 if (handler->ops->post_start(handler, handler->data))
621 goto out_abort;
622
623 if (lxc_set_state(name, handler, RUNNING)) {
624 ERROR("failed to set state to %s",
625 lxc_state2str(RUNNING));
626 goto out_abort;
627 }
628
629 lxc_sync_fini(handler);
630 return 0;
631
632out_delete_net:
633 if (clone_flags & CLONE_NEWNET)
634 lxc_delete_network(&handler->conf->network);
635out_abort:
636 lxc_abort(name, handler);
637 lxc_sync_fini(handler);
638 return -1;
639}
640
641int __lxc_start(const char *name, struct lxc_conf *conf,
642 struct lxc_operations* ops, void *data)
643{
644 struct lxc_handler *handler;
645 int err = -1;
646 int status;
647
648 handler = lxc_init(name, conf);
649 if (!handler) {
650 ERROR("failed to initialize the container");
651 return -1;
652 }
653 handler->ops = ops;
654 handler->data = data;
655
656 err = lxc_spawn(handler);
657 if (err) {
658 ERROR("failed to spawn '%s'", name);
659 goto out_fini;
660 }
661
662 /* Avoid signals from terminal */
663 LXC_TTY_ADD_HANDLER(SIGINT);
664 LXC_TTY_ADD_HANDLER(SIGQUIT);
665
666 err = lxc_poll(name, handler);
667 if (err) {
668 ERROR("mainloop exited with an error");
669 goto out_abort;
670 }
671
672 while (waitpid(handler->pid, &status, 0) < 0 && errno == EINTR)
673 continue;
674
675 /*
676 * If the child process exited but was not signaled,
677 * it didn't call reboot. This should mean it was an
678 * lxc-execute which simply exited. In any case, treat
679 * it as a 'halt'
680 */
681 if (WIFSIGNALED(status)) {
682 switch(WTERMSIG(status)) {
683 case SIGINT: /* halt */
684 DEBUG("Container halting");
685 break;
686 case SIGHUP: /* reboot */
687 DEBUG("Container rebooting");
688 handler->conf->reboot = 1;
689 break;
690 default:
691 DEBUG("unknown exit status for init: %d\n", WTERMSIG(status));
692 break;
693 }
694 }
695
696 err = lxc_error_set_and_log(handler->pid, status);
697out_fini:
698 LXC_TTY_DEL_HANDLER(SIGQUIT);
699 LXC_TTY_DEL_HANDLER(SIGINT);
700 lxc_cgroup_destroy(name);
701 lxc_fini(name, handler);
702 return err;
703
704out_abort:
705 lxc_abort(name, handler);
706 goto out_fini;
707}
708
709struct start_args {
710 char *const *argv;
711};
712
713static int start(struct lxc_handler *handler, void* data)
714{
715 struct start_args *arg = data;
716
717 NOTICE("exec'ing '%s'", arg->argv[0]);
718
719 execvp(arg->argv[0], arg->argv);
720 SYSERROR("failed to exec %s", arg->argv[0]);
721 return 0;
722}
723
724static int post_start(struct lxc_handler *handler, void* data)
725{
726 struct start_args *arg = data;
727
728 NOTICE("'%s' started with pid '%d'", arg->argv[0], handler->pid);
729 return 0;
730}
731
732static struct lxc_operations start_ops = {
733 .start = start,
734 .post_start = post_start
735};
736
737int lxc_start(const char *name, char *const argv[], struct lxc_conf *conf)
738{
739 struct start_args start_arg = {
740 .argv = argv,
741 };
742
743 if (lxc_check_inherited(conf, -1))
744 return -1;
745
746 conf->need_utmp_watch = 1;
747 return __lxc_start(name, conf, &start_ops, &start_arg);
748}
0749
=== added directory '.pc/0054-ubuntu-debug'
=== renamed directory '.pc/0054-ubuntu-debug' => '.pc/0054-ubuntu-debug.moved'
=== added file '.pc/0054-ubuntu-debug/.timestamp'
=== added directory '.pc/0054-ubuntu-debug/templates'
=== added file '.pc/0054-ubuntu-debug/templates/lxc-ubuntu-cloud.in'
--- .pc/0054-ubuntu-debug/templates/lxc-ubuntu-cloud.in 1970-01-01 00:00:00 +0000
+++ .pc/0054-ubuntu-debug/templates/lxc-ubuntu-cloud.in 2012-03-02 15:11:19 +0000
@@ -0,0 +1,304 @@
1#!/bin/bash
2
3# template script for generating ubuntu container for LXC based on daily cloud
4# images
5#
6# Copyright © 2012 Serge Hallyn <serge.hallyn@canonical.com>
7#
8# This program is free software; you can redistribute it and/or modify
9# it under the terms of the GNU General Public License version 2, as
10# published by the Free Software Foundation.
11
12# This program is distributed in the hope that it will be useful,
13# but WITHOUT ANY WARRANTY; without even the implied warranty of
14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15# GNU General Public License for more details.
16
17# You should have received a copy of the GNU General Public License along
18# with this program; if not, write to the Free Software Foundation, Inc.,
19# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20#
21
22set -e
23
24if [ -r /etc/default/lxc ]; then
25 . /etc/default/lxc
26fi
27
28copy_configuration()
29{
30 path=$1
31 rootfs=$2
32 name=$3
33 arch=$4
34
35 if [ $arch = "i386" ]; then
36 arch="i686"
37 fi
38
39 # if there is exactly one veth network entry, make sure it has an
40 # associated hwaddr.
41 nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l`
42 if [ $nics -eq 1 ]; then
43 grep -q "^lxc.network.hwaddr" $path/config || cat <<EOF >> $path/config
44lxc.network.hwaddr= 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')
45EOF
46 fi
47
48 cat <<EOF >> $path/config
49lxc.utsname = $name
50
51lxc.tty = 4
52lxc.pts = 1024
53lxc.rootfs = $rootfs
54lxc.mount = $path/fstab
55lxc.arch = $arch
56lxc.cap.drop = sys_module mac_admin
57
58lxc.cgroup.devices.deny = a
59# Allow any mknod (but not using the node)
60lxc.cgroup.devices.allow = c *:* m
61lxc.cgroup.devices.allow = b *:* m
62# /dev/null and zero
63lxc.cgroup.devices.allow = c 1:3 rwm
64lxc.cgroup.devices.allow = c 1:5 rwm
65# consoles
66lxc.cgroup.devices.allow = c 5:1 rwm
67lxc.cgroup.devices.allow = c 5:0 rwm
68#lxc.cgroup.devices.allow = c 4:0 rwm
69#lxc.cgroup.devices.allow = c 4:1 rwm
70# /dev/{,u}random
71lxc.cgroup.devices.allow = c 1:9 rwm
72lxc.cgroup.devices.allow = c 1:8 rwm
73lxc.cgroup.devices.allow = c 136:* rwm
74lxc.cgroup.devices.allow = c 5:2 rwm
75# rtc
76lxc.cgroup.devices.allow = c 254:0 rwm
77#fuse
78lxc.cgroup.devices.allow = c 10:229 rwm
79#tun
80lxc.cgroup.devices.allow = c 10:200 rwm
81#full
82lxc.cgroup.devices.allow = c 1:7 rwm
83#hpet
84lxc.cgroup.devices.allow = c 10:228 rwm
85#kvm
86lxc.cgroup.devices.allow = c 10:232 rwm
87EOF
88
89 cat <<EOF > $path/fstab
90proc $rootfs/proc proc nodev,noexec,nosuid 0 0
91sysfs $rootfs/sys sysfs defaults 0 0
92EOF
93
94 return 0
95}
96
97usage()
98{
99 cat <<EOF
100LXC Container configuration for Ubuntu Cloud images.
101
102Generic Options
103[ -r | --release <release> ]: Release name of container, defaults to host
104[ -a | --arch ]: Arhcitecture of container, defaults to host arcitecture
105[ -C | --cloud ]: Configure container for use with meta-data service, defaults to no
106[ -T | --tarball ]: Location of tarball
107
108Options, mutually exclusive of "-C" and "--cloud":
109 [ -i | --hostid ]: HostID for cloud-init, defaults to random string
110 [ -u | --userdata ]: Cloud-init user-data file to configure container on start
111 [ -S | --auth-key ]: SSH Public key file to inject into container
112 [ -L | --nolocales ]: Do not copy host's locales into container
113
114EOF
115 return 0
116}
117
118options=$(getopt -o a:hp:r:n:Fi:CLS:T: -l arch:,help,path:,release:,name:,flush-cache,hostid:,auth-key:,cloud,no_locales,tarball: -- "$@")
119if [ $? -ne 0 ]; then
120 usage $(basename $0)
121 exit 1
122fi
123eval set -- "$options"
124
125release=lucid
126if [ -f /etc/lsb-release ]; then
127 . /etc/lsb-release
128 case "$DISTRIB_CODENAME" in
129 lucid|maverick|natty|oneiric|precise)
130 release=$DISTRIB_CODENAME
131 ;;
132 esac
133fi
134
135arch=$(arch)
136
137# Code taken from debootstrap
138if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then
139 arch=`/usr/bin/dpkg --print-architecture`
140elif type udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then
141 arch=`/usr/bin/udpkg --print-architecture`
142else
143 arch=$(arch)
144 if [ "$arch" = "i686" ]; then
145 arch="i386"
146 elif [ "$arch" = "x86_64" ]; then
147 arch="amd64"
148 elif [ "$arch" = "armv7l" ]; then
149 arch="armel"
150 fi
151fi
152
153hostarch=$arch
154cloud=0
155locales=1
156flushcache=0
157while true
158do
159 case "$1" in
160 -h|--help) usage $0 && exit 0;;
161 -p|--path) path=$2; shift 2;;
162 -n|--name) name=$2; shift 2;;
163 -F|--flush-cache) flushcache=1; shift 1;;
164 -r|--release) release=$2; shift 2;;
165 -a|--arch) arch=$2; shift 2;;
166 -i|--hostid) host_id=$2; shift 2;;
167 -u|--userdata) userdata=$2; shift 2;;
168 -C|--cloud) cloud=1; shift 1;;
169 -S|--auth-key) auth_key=$2; shift 2;;
170 -L|--no_locales) locales=0; shift 2;;
171 -T|--tarball) tarball=$2; shift 2;;
172 --) shift 1; break ;;
173 *) break ;;
174 esac
175done
176
177if [ "$arch" == "i686" ]; then
178 arch=i386
179fi
180
181if [ $hostarch = "i386" -a $arch = "amd64" ]; then
182 echo "can't create amd64 container on i386"
183 exit 1
184fi
185
186if [ $arch != "i386" -a $arch != "amd64" ]; then
187 echo "Only i386 and amd64 are supported by the ubuntu cloud template."
188 exit 1
189fi
190
191if [ -z "$path" ]; then
192 echo "'path' parameter is required"
193 exit 1
194fi
195
196if [ "$(id -u)" != "0" ]; then
197 echo "This script should be run as 'root'"
198 exit 1
199fi
200
201rootfs=$path/rootfs
202
203type ubuntu-cloudimg-query
204type wget
205
206# determine the url, tarball, and directory names
207# download if needed
208cache="/var/cache/lxc/cloud-$release"
209
210mkdir -p $cache
211
212if [ -n "$tarball" ]; then
213 url2="$tarball"
214else
215 url1=`ubuntu-cloudimg-query precise daily $arch --format "%{url}\n"`
216 url2=`echo $url1 | sed -e 's/.tar.gz/-root\0/'`
217fi
218
219filename=`basename $url2`
220
221mkdir -p /var/lock/subsys/
222(
223 flock -n -x 200
224
225 cd $cache
226 if [ $flushcache -eq 1 ]; then
227 echo "Clearing the cached images"
228 rm -f $filename
229 fi
230
231 if [ ! -f $filename ]; then
232 wget $url2
233 fi
234
235 echo "Extracting rootfs"
236 mkdir -p $rootfs
237 cd $rootfs
238 tar -zxf $cache/$filename
239
240
241 if [ $cloud -eq 0 ]; then
242 echo "Configuring for running outside of a cloud environment"
243 echo "If you want to configure for a cloud evironment, please use '-- -C' to create the container"
244
245 seed_d=$rootfs/var/lib/cloud/seed/nocloud-net
246 rhostid=$(uuidgen | cut -c -8)
247 host_id=${hostid:-$rhostid}
248 mkdir -p $seed_d
249
250 cat > "$seed_d/meta-data" <<EOF
251instance_id: lxc-$host_id
252EOF
253
254 rm $rootfs/etc/hostname
255
256 if [ $locales -eq 1 ]; then
257 cp /usr/lib/locale/locale-archive $rootfs/usr/lib/locale/locale-archive
258 fi
259
260
261 if [ -n "$auth_key" -a -f "$auth_key" ]; then
262 u_path="/home/ubuntu/.ssh"
263 root_u_path="$rootfs/$u_path"
264 mkdir -p $root_u_path
265 cp $auth_key "$root_u_path/authorized_keys"
266 chroot $rootfs chown -R ubuntu: "$u_path"
267
268 echo "Inserted SSH public key from $auth_key into /home/ubuntu/.ssh/authorized_keys"
269 fi
270
271 if [ ! -f $userdata ]; then
272 cp $userdata $data_d/user-data
273 else
274
275 if [ -z "$MIRROR" ]; then
276 MIRROR="http://archive.ubuntu.com/ubuntu"
277 fi
278
279 cat > "$seed_d/user-data" <<EOF
280#cloud-config
281output: {all: '| tee -a /var/log/cloud-init-output.log'}
282apt-mirror: $MIRROR
283manage_etc_hosts: localhost
284locale: $(/usr/bin/locale | awk -F= '/LANG=/ {print$NF}')
285EOF
286
287 fi
288
289 chroot $rootfs /usr/sbin/usermod -U ubuntu
290 echo "Please login as user ubuntu with password ubuntu."
291
292 else
293
294 echo "Configured for running in a cloud environment."
295 echo "If you do not have a meta-data service, this container will likely be useless."
296
297 fi
298
299) 200>/var/lock/subsys/lxc-ubucloud
300
301copy_configuration $path $rootfs $name $arch
302
303echo "Container $name created."
304exit 0
0305
=== added file '.pc/0054-ubuntu-debug/templates/lxc-ubuntu.in'
--- .pc/0054-ubuntu-debug/templates/lxc-ubuntu.in 1970-01-01 00:00:00 +0000
+++ .pc/0054-ubuntu-debug/templates/lxc-ubuntu.in 2012-03-02 15:11:19 +0000
@@ -0,0 +1,665 @@
1#!/bin/bash
2
3#
4# template script for generating ubuntu container for LXC
5#
6# This script consolidates and extends the existing lxc ubuntu scripts
7#
8
9# Copyright © 2011 Serge Hallyn <serge.hallyn@canonical.com>
10# Copyright © 2010 Wilhelm Meier
11# Author: Wilhelm Meier <wilhelm.meier@fh-kl.de>
12#
13# This program is free software; you can redistribute it and/or modify
14# it under the terms of the GNU General Public License version 2, as
15# published by the Free Software Foundation.
16
17# This program is distributed in the hope that it will be useful,
18# but WITHOUT ANY WARRANTY; without even the implied warranty of
19# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20# GNU General Public License for more details.
21
22# You should have received a copy of the GNU General Public License along
23# with this program; if not, write to the Free Software Foundation, Inc.,
24# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25#
26
27set -e
28
29if [ -r /etc/default/lxc ]; then
30 . /etc/default/lxc
31fi
32
33configure_ubuntu()
34{
35 rootfs=$1
36 hostname=$2
37 release=$3
38
39 # configure the network using the dhcp
40 cat <<EOF > $rootfs/etc/network/interfaces
41auto lo
42iface lo inet loopback
43
44auto eth0
45iface eth0 inet dhcp
46EOF
47
48 # set the hostname
49 cat <<EOF > $rootfs/etc/hostname
50$hostname
51EOF
52 # set minimal hosts
53 cat <<EOF > $rootfs/etc/hosts
54127.0.0.1 localhost $hostname
55EOF
56
57 if [ "$release" != "precise" ]; then
58 # suppress log level output for udev
59 sed -i "s/=\"err\"/=0/" $rootfs/etc/udev/udev.conf
60
61 # remove jobs for consoles 5 and 6 since we only create 4 consoles in
62 # this template
63 rm -f $rootfs/etc/init/tty{5,6}.conf
64 fi
65
66 if [ -z "$bindhome" ]; then
67 chroot $rootfs useradd --create-home -s /bin/bash ubuntu
68 echo "ubuntu:ubuntu" | chroot $rootfs chpasswd
69 fi
70
71 return 0
72}
73
74# finish setting up the user in the container by injecting ssh key and
75# adding sudo group membership.
76# passed-in user is either 'ubuntu' or the user to bind in from host.
77finalize_user()
78{
79 user=$1
80
81 if [ "$release" = "precise" ]; then
82 groups="sudo"
83 else
84 groups="sudo admin"
85 fi
86
87 for group in $groups; do
88 chroot $rootfs groupadd --system $group >/dev/null 2>&1 || true
89 chroot $rootfs adduser ${user} $group >/dev/null 2>&1 || true
90 done
91
92 if [ -n "$auth_key" -a -f "$auth_key" ]; then
93 u_path="/home/${user}/.ssh"
94 root_u_path="$rootfs/$u_path"
95 mkdir -p $root_u_path
96 cp $auth_key "$root_u_path/authorized_keys"
97 chroot $rootfs chown -R ${user}: "$u_path"
98
99 echo "Inserted SSH public key from $auth_key into /home/${user}/.ssh/authorized_keys"
100 fi
101 return 0
102}
103
104write_sourceslist()
105{
106 # $1 => path to the rootfs
107 # $2 => architecture we want to add
108 # $3 => whether to use the multi-arch syntax or not
109
110 case $2 in
111 amd64|i386)
112 MIRROR=${MIRROR:-http://archive.ubuntu.com/ubuntu}
113 SECURITY_MIRROR=${SECURITY_MIRROR:-http://security.ubuntu.com/ubuntu}
114 ;;
115 sparc)
116 case $SUITE in
117 gutsy)
118 MIRROR=${MIRROR:-http://archive.ubuntu.com/ubuntu}
119 SECURITY_MIRROR=${SECURITY_MIRRORMIRROR:-http://security.ubuntu.com/ubuntu}
120 ;;
121 *)
122 MIRROR=${MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
123 SECURITY_MIRROR=${SECURITY_MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
124 ;;
125 esac
126 ;;
127 *)
128 MIRROR=${MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
129 SECURITY_MIRROR=${SECURITY_MIRROR:-http://ports.ubuntu.com/ubuntu-ports}
130 ;;
131 esac
132 if [ -n "$3" ]; then
133 cat >> "$1/etc/apt/sources.list" << EOF
134deb [arch=$2] $MIRROR ${release} main restricted universe multiverse
135deb [arch=$2] $MIRROR ${release}-updates main restricted universe multiverse
136deb [arch=$2] $SECURITY_MIRROR ${release}-security main restricted universe multiverse
137EOF
138 else
139 cat >> "$1/etc/apt/sources.list" << EOF
140deb $MIRROR ${release} main restricted universe multiverse
141deb $MIRROR ${release}-updates main restricted universe multiverse
142deb $SECURITY_MIRROR ${release}-security main restricted universe multiverse
143EOF
144 fi
145}
146
147download_ubuntu()
148{
149 cache=$1
150 arch=$2
151 release=$3
152
153 if [ $release = "lucid" ]; then
154 packages=dialog,apt,apt-utils,resolvconf,iproute,inetutils-ping,vim,dhcp3-client,ssh,lsb-release,gnupg
155 elif [ $release = "maverick" ]; then
156 packages=dialog,apt,apt-utils,resolvconf,iproute,inetutils-ping,vim,dhcp3-client,ssh,lsb-release,gnupg,netbase
157 elif [ $release = "natty" ]; then
158 packages=dialog,apt,apt-utils,resolvconf,iproute,inetutils-ping,vim,isc-dhcp-client,isc-dhcp-common,ssh,lsb-release,gnupg,netbase
159 else
160 packages=dialog,apt,apt-utils,iproute,inetutils-ping,vim,isc-dhcp-client,isc-dhcp-common,ssh,lsb-release,gnupg,netbase,ubuntu-keyring
161 fi
162 echo "installing packages: $packages"
163
164 # check the mini ubuntu was not already downloaded
165 mkdir -p "$cache/partial-$arch"
166 if [ $? -ne 0 ]; then
167 echo "Failed to create '$cache/partial-$arch' directory"
168 return 1
169 fi
170
171 # download a mini ubuntu into a cache
172 echo "Downloading ubuntu $release minimal ..."
173 if [ -n "$(which qemu-debootstrap)" ]; then
174 qemu-debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR
175 else
176 debootstrap --verbose --components=main,universe --arch=$arch --include=$packages $release $cache/partial-$arch $MIRROR
177 fi
178
179 if [ $? -ne 0 ]; then
180 echo "Failed to download the rootfs, aborting."
181 return 1
182 fi
183
184 # Serge isn't sure whether we should avoid doing this when
185 # $release == `distro-info -d`
186 echo "Installing updates"
187 > $cache/partial-$arch/etc/apt/sources.list
188 write_sourceslist $cache/partial-$arch/ $arch
189
190 chroot "$1/partial-${arch}" apt-get update
191 if [ $? -ne 0 ]; then
192 echo "Failed to update the apt cache"
193 return 1
194 fi
195 cat > "$1/partial-${arch}"/usr/sbin/policy-rc.d << EOF
196#!/bin/sh
197exit 101
198EOF
199 chmod +x "$1/partial-${arch}"/usr/sbin/policy-rc.d
200
201 lxc-unshare -s MOUNT -- chroot "$1/partial-${arch}" apt-get dist-upgrade -y
202 ret=$?
203 rm -f "$1/partial-${arch}"/usr/sbin/policy-rc.d
204
205 if [ $ret -ne 0 ]; then
206 echo "Failed to upgrade the cache"
207 return 1
208 fi
209
210 mv "$1/partial-$arch" "$1/rootfs-$arch"
211 echo "Download complete"
212 return 0
213}
214
215copy_ubuntu()
216{
217 cache=$1
218 arch=$2
219 rootfs=$3
220
221 # make a local copy of the miniubuntu
222 echo "Copying rootfs to $rootfs ..."
223 mkdir -p $rootfs
224 rsync -a $cache/rootfs-$arch/ $rootfs/ || return 1
225 return 0
226}
227
228install_ubuntu()
229{
230 rootfs=$1
231 release=$2
232 flushcache=$3
233 cache="/var/cache/lxc/$release"
234 mkdir -p /var/lock/subsys/
235 (
236 flock -n -x 200
237 if [ $? -ne 0 ]; then
238 echo "Cache repository is busy."
239 return 1
240 fi
241
242
243 if [ $flushcache -eq 1 ]; then
244 echo "Flushing cache..."
245 rm -rf "$cache/partial-$arch"
246 rm -rf "$cache/rootfs-$arch"
247 fi
248
249 echo "Checking cache download in $cache/rootfs-$arch ... "
250 if [ ! -e "$cache/rootfs-$arch" ]; then
251 download_ubuntu $cache $arch $release
252 if [ $? -ne 0 ]; then
253 echo "Failed to download 'ubuntu $release base'"
254 return 1
255 fi
256 fi
257
258 echo "Copy $cache/rootfs-$arch to $rootfs ... "
259 copy_ubuntu $cache $arch $rootfs
260 if [ $? -ne 0 ]; then
261 echo "Failed to copy rootfs"
262 return 1
263 fi
264
265 return 0
266
267 ) 200>/var/lock/subsys/lxc
268
269 return $?
270}
271
272copy_configuration()
273{
274 path=$1
275 rootfs=$2
276 name=$3
277 arch=$4
278 release=$5
279
280 if [ $arch = "i386" ]; then
281 arch="i686"
282 fi
283
284 ttydir=""
285 if [ $release = "precise" ]; then
286 ttydir=" lxc"
287 fi
288
289 # if there is exactly one veth network entry, make sure it has an
290 # associated hwaddr.
291 nics=`grep -e '^lxc\.network\.type[ \t]*=[ \t]*veth' $path/config | wc -l`
292 if [ $nics -eq 1 ]; then
293 grep -q "^lxc.network.hwaddr" $path/config || cat <<EOF >> $path/config
294lxc.network.hwaddr= 00:16:3e:$(openssl rand -hex 3| sed 's/\(..\)/\1:/g; s/.$//')
295EOF
296 fi
297
298 cat <<EOF >> $path/config
299lxc.utsname = $name
300
301lxc.devttydir =$ttydir
302lxc.tty = 4
303lxc.pts = 1024
304lxc.rootfs = $rootfs
305lxc.mount = $path/fstab
306lxc.arch = $arch
307lxc.cap.drop = sys_module mac_admin
308
309lxc.cgroup.devices.deny = a
310# Allow any mknod (but not using the node)
311lxc.cgroup.devices.allow = c *:* m
312lxc.cgroup.devices.allow = b *:* m
313# /dev/null and zero
314lxc.cgroup.devices.allow = c 1:3 rwm
315lxc.cgroup.devices.allow = c 1:5 rwm
316# consoles
317lxc.cgroup.devices.allow = c 5:1 rwm
318lxc.cgroup.devices.allow = c 5:0 rwm
319#lxc.cgroup.devices.allow = c 4:0 rwm
320#lxc.cgroup.devices.allow = c 4:1 rwm
321# /dev/{,u}random
322lxc.cgroup.devices.allow = c 1:9 rwm
323lxc.cgroup.devices.allow = c 1:8 rwm
324lxc.cgroup.devices.allow = c 136:* rwm
325lxc.cgroup.devices.allow = c 5:2 rwm
326# rtc
327lxc.cgroup.devices.allow = c 254:0 rwm
328#fuse
329lxc.cgroup.devices.allow = c 10:229 rwm
330#tun
331lxc.cgroup.devices.allow = c 10:200 rwm
332#full
333lxc.cgroup.devices.allow = c 1:7 rwm
334#hpet
335lxc.cgroup.devices.allow = c 10:228 rwm
336#kvm
337lxc.cgroup.devices.allow = c 10:232 rwm
338EOF
339
340 cat <<EOF > $path/fstab
341proc $rootfs/proc proc nodev,noexec,nosuid 0 0
342sysfs $rootfs/sys sysfs defaults 0 0
343EOF
344
345 if [ $? -ne 0 ]; then
346 echo "Failed to add configuration"
347 return 1
348 fi
349
350 return 0
351}
352
353trim()
354{
355 rootfs=$1
356 release=$2
357
358 # provide the lxc service
359 cat <<EOF > $rootfs/etc/init/lxc.conf
360# fake some events needed for correct startup other services
361
362description "Container Upstart"
363
364start on startup
365
366script
367 rm -rf /var/run/*.pid
368 rm -rf /var/run/network/*
369 /sbin/initctl emit stopped JOB=udevtrigger --no-wait
370 /sbin/initctl emit started JOB=udev --no-wait
371end script
372EOF
373
374 # fix buggus runlevel with sshd
375 cat <<EOF > $rootfs/etc/init/ssh.conf
376# ssh - OpenBSD Secure Shell server
377#
378# The OpenSSH server provides secure shell access to the system.
379
380description "OpenSSH server"
381
382start on filesystem
383stop on runlevel [!2345]
384
385expect fork
386respawn
387respawn limit 10 5
388umask 022
389# replaces SSHD_OOM_ADJUST in /etc/default/ssh
390oom never
391
392pre-start script
393 test -x /usr/sbin/sshd || { stop; exit 0; }
394 test -e /etc/ssh/sshd_not_to_be_run && { stop; exit 0; }
395 test -c /dev/null || { stop; exit 0; }
396
397 mkdir -p -m0755 /var/run/sshd
398end script
399
400# if you used to set SSHD_OPTS in /etc/default/ssh, you can change the
401# 'exec' line here instead
402exec /usr/sbin/sshd
403EOF
404
405 cat <<EOF > $rootfs/etc/init/console.conf
406# console - getty
407#
408# This service maintains a console on tty1 from the point the system is
409# started until it is shut down again.
410
411start on stopped rc RUNLEVEL=[2345]
412stop on runlevel [!2345]
413
414respawn
415exec /sbin/getty -8 38400 /dev/console
416EOF
417
418 cat <<EOF > $rootfs/lib/init/fstab
419# /lib/init/fstab: cleared out for bare-bones lxc
420EOF
421
422 # reconfigure some services
423 if [ -z "$LANG" ]; then
424 chroot $rootfs locale-gen en_US.UTF-8
425 chroot $rootfs update-locale LANG=en_US.UTF-8
426 else
427 chroot $rootfs locale-gen $LANG
428 chroot $rootfs update-locale LANG=$LANG
429 fi
430
431 # remove pointless services in a container
432 chroot $rootfs /usr/sbin/update-rc.d -f ondemand remove
433
434 chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls u*.conf); do mv $f $f.orig; done'
435 chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls tty[2-9].conf); do mv $f $f.orig; done'
436 chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls plymouth*.conf); do mv $f $f.orig; done'
437 chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls hwclock*.conf); do mv $f $f.orig; done'
438 chroot $rootfs /bin/bash -c 'cd /etc/init; for f in $(ls module*.conf); do mv $f $f.orig; done'
439
440 # if this isn't lucid, then we need to twiddle the network upstart bits :(
441 if [ $release != "lucid" ]; then
442 sed -i 's/^.*emission handled.*$/echo Emitting lo/' $rootfs/etc/network/if-up.d/upstart
443 fi
444}
445
446post_process()
447{
448 rootfs=$1
449 release=$2
450 trim_container=$3
451
452 if [ $trim_container -eq 1 ]; then
453 trim $rootfs $release
454 elif [ $release = "lucid" -o $release = "maverick" -o $release = "natty" \
455 -o $release = "oneiric" ]; then
456 # for lucid and maverick, if not trimming, then add the ubuntu-virt
457 # ppa and install lxcguest
458 if [ $release = "lucid" -o $release = "maverick" ]; then
459 chroot $rootfs apt-get install --force-yes -y python-software-properties
460 chroot $rootfs add-apt-repository ppa:ubuntu-virt/ppa
461 fi
462 cresolvonf="${rootfs}/etc/resolv.conf"
463 mv $cresolvonf ${cresolvonf}.lxcbak
464 cat /etc/resolv.conf > ${cresolvonf}
465 chroot $rootfs apt-get update
466 chroot $rootfs apt-get install --force-yes -y lxcguest
467 rm -f ${cresolvonf}
468 mv ${cresolvonf}.lxcbak ${cresolvonf}
469 fi
470
471 # If the container isn't running a native architecture, setup multiarch
472 if [ -x "$(ls -1 ${rootfs}/usr/bin/qemu-*-static 2>/dev/null)" ]; then
473 mkdir -p ${rootfs}/etc/dpkg/dpkg.cfg.d
474 echo "foreign-architecture ${hostarch}" > ${rootfs}/etc/dpkg/dpkg.cfg.d/lxc-multiarch
475
476 # Save existing value of MIRROR and SECURITY_MIRROR
477 DEFAULT_MIRROR=$MIRROR
478 DEFAULT_SECURITY_MIRROR=$SECURITY_MIRROR
479
480 # Write a new sources.list containing both native and multiarch entries
481 > ${rootfs}/etc/apt/sources.list
482 write_sourceslist $rootfs $arch "native"
483
484 MIRROR=$DEFAULT_MIRROR
485 SECURITY_MIRROR=$DEFAULT_SECURITY_MIRROR
486 write_sourceslist $rootfs $hostarch "multiarch"
487
488 # Finally update the lists and install upstart using the host architecture
489 chroot $rootfs apt-get update
490 chroot $rootfs apt-get install --force-yes -y --no-install-recommends upstart:${hostarch} mountall:amd64 iproute:amd64 isc-dhcp-client:amd64
491 fi
492}
493
494do_bindhome()
495{
496 rootfs=$1
497 user=$2
498
499 # copy /etc/passwd, /etc/shadow, and /etc/group entries into container
500 pwd=`getent passwd $user` || { echo "Failed to copy password entry for $user"; false; }
501 echo $pwd >> $rootfs/etc/passwd
502
503 # make sure user's shell exists in the container
504 shell=`echo $pwd | cut -d: -f 7`
505 if [ ! -x $rootfs/$shell ]; then
506 echo "shell $shell for user $user was not found in the container."
507 pkg=`dpkg -S $(readlink -m $shell) | cut -d ':' -f1`
508 echo "Installing $pkg"
509 chroot $rootfs apt-get --force-yes -y install $pkg
510 fi
511
512 shad=`getent shadow $user`
513 echo "$shad" >> $rootfs/etc/shadow
514
515 # bind-mount the user's path into the container's /home
516 h=`getent passwd $user | cut -d: -f 6`
517 mkdir -p $rootfs/$h
518 echo "$h $rootfs/$h none bind 0 0" >> $path/fstab
519
520 # Make sure the group exists in container
521 chroot $rootfs getent group $user || { \
522 grp=`getent group $user`
523 echo "$grp" >> $rootfs/etc/group
524 }
525}
526
527usage()
528{
529 cat <<EOF
530$1 -h|--help [-a|--arch] [-b|--bindhome <user>] [--trim]
531 [-F | --flush-cache] [-r|--release <release>] [ -S | --auth-key <keyfile>]
532release: lucid | maverick | natty | oneiric | precise
533trim: make a minimal (faster, but not upgrade-safe) container
534bindhome: bind <user>'s home into the container
535 The ubuntu user will not be created, and <user> will have
536 sudo access.
537arch: amd64 or i386: defaults to host arch
538auth-key: SSH Public key file to inject into container
539EOF
540 return 0
541}
542
543options=$(getopt -o a:b:hp:r:xn:FS: -l arch:,bindhome:,help,path:,release:,trim,name:,flush-cache,auth-key: -- "$@")
544if [ $? -ne 0 ]; then
545 usage $(basename $0)
546 exit 1
547fi
548eval set -- "$options"
549
550release=lucid
551if [ -f /etc/lsb-release ]; then
552 . /etc/lsb-release
553 case "$DISTRIB_CODENAME" in
554 lucid|maverick|natty|oneiric|precise)
555 release=$DISTRIB_CODENAME
556 ;;
557 esac
558fi
559
560bindhome=
561arch=$(arch)
562
563# Code taken from debootstrap
564if [ -x /usr/bin/dpkg ] && /usr/bin/dpkg --print-architecture >/dev/null 2>&1; then
565 arch=`/usr/bin/dpkg --print-architecture`
566elif type udpkg >/dev/null 2>&1 && udpkg --print-architecture >/dev/null 2>&1; then
567 arch=`/usr/bin/udpkg --print-architecture`
568else
569 arch=$(arch)
570 if [ "$arch" = "i686" ]; then
571 arch="i386"
572 elif [ "$arch" = "x86_64" ]; then
573 arch="amd64"
574 elif [ "$arch" = "armv7l" ]; then
575 arch="armel"
576 fi
577fi
578
579trim_container=0
580hostarch=$arch
581flushcache=0
582while true
583do
584 case "$1" in
585 -h|--help) usage $0 && exit 0;;
586 -p|--path) path=$2; shift 2;;
587 -n|--name) name=$2; shift 2;;
588 -F|--flush-cache) flushcache=1; shift 1;;
589 -r|--release) release=$2; shift 2;;
590 -b|--bindhome) bindhome=$2; shift 2;;
The diff has been truncated for viewing.

Subscribers

People subscribed via source and target branches

to all changes: