summaryrefslogtreecommitdiffstats
path: root/scripts/lib/mic/chroot.py
diff options
context:
space:
mode:
authorTom Zanussi <tom.zanussi@linux.intel.com>2013-08-24 15:31:34 +0000
committerRichard Purdie <richard.purdie@linuxfoundation.org>2013-10-01 22:56:03 +0100
commit9fc88f96d40b17c90bac53b90045a87b2d2cff84 (patch)
tree63010e5aabf895697655baf89bd668d6752b3f97 /scripts/lib/mic/chroot.py
parent53a1d9a788fd9f970af980da2ab975cca60685c4 (diff)
downloadpoky-9fc88f96d40b17c90bac53b90045a87b2d2cff84.tar.gz
wic: Add mic w/pykickstart
This is the starting point for the implemention described in [YOCTO 3847] which came to the conclusion that it would make sense to use kickstart syntax to implement image creation in OpenEmbedded. I subsequently realized that there was an existing tool that already implemented image creation using kickstart syntax, the Tizen/Meego mic tool. As such, it made sense to use that as a starting point - this commit essentially just copies the relevant Python code from the MIC tool to the scripts/lib dir, where it can be accessed by the previously created wic tool. Most of this will be removed or renamed by later commits, since we're initially focusing on partitioning only. Care should be taken so that we can easily add back any additional functionality should we decide later to expand the tool, though (we may also want to contribute our local changes to the mic tool to the Tizen project if it makes sense, and therefore should avoid gratuitous changes to the original code if possible). Added the /mic subdir from Tizen mic repo as a starting point: git clone git://review.tizen.org/tools/mic.git For reference, the top commit: commit 20164175ddc234a17b8a12c33d04b012347b1530 Author: Gui Chen <gui.chen@intel.com> Date: Sun Jun 30 22:32:16 2013 -0400 bump up to 0.19.2 Also added the /plugins subdir, moved to under the /mic subdir (to match the default plugin_dir location in mic.conf.in, which was renamed to yocto-image.conf (moved and renamed by later patches) and put into /scripts. (From OE-Core rev: 31f0360f1fd4ebc9dfcaed42d1c50d2448b4632e) Signed-off-by: Tom Zanussi <tom.zanussi@linux.intel.com> Signed-off-by: Saul Wold <sgw@linux.intel.com> Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'scripts/lib/mic/chroot.py')
-rw-r--r--scripts/lib/mic/chroot.py343
1 files changed, 343 insertions, 0 deletions
diff --git a/scripts/lib/mic/chroot.py b/scripts/lib/mic/chroot.py
new file mode 100644
index 0000000000..99fb9a2c17
--- /dev/null
+++ b/scripts/lib/mic/chroot.py
@@ -0,0 +1,343 @@
1#!/usr/bin/python -tt
2#
3# Copyright (c) 2009, 2010, 2011 Intel, Inc.
4#
5# This program is free software; you can redistribute it and/or modify it
6# under the terms of the GNU General Public License as published by the Free
7# Software Foundation; version 2 of the License
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12# for more details.
13#
14# You should have received a copy of the GNU General Public License along
15# with this program; if not, write to the Free Software Foundation, Inc., 59
16# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17
18from __future__ import with_statement
19import os
20import shutil
21import subprocess
22
23from mic import msger
24from mic.conf import configmgr
25from mic.utils import misc, errors, runner, fs_related
26
27chroot_lockfd = -1
28chroot_lock = ""
29BIND_MOUNTS = (
30 "/proc",
31 "/proc/sys/fs/binfmt_misc",
32 "/sys",
33 "/dev",
34 "/dev/pts",
35 "/dev/shm",
36 "/var/lib/dbus",
37 "/var/run/dbus",
38 "/var/lock",
39 )
40
41def cleanup_after_chroot(targettype,imgmount,tmpdir,tmpmnt):
42 if imgmount and targettype == "img":
43 imgmount.cleanup()
44
45 if tmpdir:
46 shutil.rmtree(tmpdir, ignore_errors = True)
47
48 if tmpmnt:
49 shutil.rmtree(tmpmnt, ignore_errors = True)
50
51def check_bind_mounts(chrootdir, bindmounts):
52 chrootmounts = []
53 for mount in bindmounts.split(";"):
54 if not mount:
55 continue
56
57 srcdst = mount.split(":")
58 if len(srcdst) == 1:
59 srcdst.append("none")
60
61 if not os.path.isdir(srcdst[0]):
62 return False
63
64 if srcdst[1] == "" or srcdst[1] == "none":
65 srcdst[1] = None
66
67 if srcdst[0] in BIND_MOUNTS or srcdst[0] == '/':
68 continue
69
70 if chrootdir:
71 if not srcdst[1]:
72 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[0]))
73 else:
74 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
75
76 tmpdir = chrootdir + "/" + srcdst[1]
77 if os.path.isdir(tmpdir):
78 msger.warning("Warning: dir %s has existed." % tmpdir)
79
80 return True
81
82def cleanup_mounts(chrootdir):
83 umountcmd = misc.find_binary_path("umount")
84 abs_chrootdir = os.path.abspath(chrootdir)
85 mounts = open('/proc/mounts').readlines()
86 for line in reversed(mounts):
87 if abs_chrootdir not in line:
88 continue
89
90 point = line.split()[1]
91
92 # '/' to avoid common name prefix
93 if abs_chrootdir == point or point.startswith(abs_chrootdir + '/'):
94 args = [ umountcmd, "-l", point ]
95 ret = runner.quiet(args)
96 if ret != 0:
97 msger.warning("failed to unmount %s" % point)
98
99 return 0
100
101def setup_chrootenv(chrootdir, bindmounts = None, mountparent = True):
102 global chroot_lockfd, chroot_lock
103
104 def get_bind_mounts(chrootdir, bindmounts, mountparent = True):
105 chrootmounts = []
106 if bindmounts in ("", None):
107 bindmounts = ""
108
109 for mount in bindmounts.split(";"):
110 if not mount:
111 continue
112
113 srcdst = mount.split(":")
114 srcdst[0] = os.path.abspath(os.path.expanduser(srcdst[0]))
115 if len(srcdst) == 1:
116 srcdst.append("none")
117
118 # if some bindmount is not existed, but it's created inside
119 # chroot, this is not expected
120 if not os.path.exists(srcdst[0]):
121 os.makedirs(srcdst[0])
122
123 if not os.path.isdir(srcdst[0]):
124 continue
125
126 if srcdst[0] in BIND_MOUNTS or srcdst[0] == '/':
127 msger.verbose("%s will be mounted by default." % srcdst[0])
128 continue
129
130 if srcdst[1] == "" or srcdst[1] == "none":
131 srcdst[1] = None
132 else:
133 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
134 if os.path.isdir(chrootdir + "/" + srcdst[1]):
135 msger.warning("%s has existed in %s , skip it."\
136 % (srcdst[1], chrootdir))
137 continue
138
139 chrootmounts.append(fs_related.BindChrootMount(srcdst[0],
140 chrootdir,
141 srcdst[1]))
142
143 """Default bind mounts"""
144 for pt in BIND_MOUNTS:
145 if not os.path.exists(pt):
146 continue
147 chrootmounts.append(fs_related.BindChrootMount(pt,
148 chrootdir,
149 None))
150
151 if mountparent:
152 chrootmounts.append(fs_related.BindChrootMount("/",
153 chrootdir,
154 "/parentroot",
155 "ro"))
156
157 for kernel in os.listdir("/lib/modules"):
158 chrootmounts.append(fs_related.BindChrootMount(
159 "/lib/modules/"+kernel,
160 chrootdir,
161 None,
162 "ro"))
163
164 return chrootmounts
165
166 def bind_mount(chrootmounts):
167 for b in chrootmounts:
168 msger.verbose("bind_mount: %s -> %s" % (b.src, b.dest))
169 b.mount()
170
171 def setup_resolv(chrootdir):
172 try:
173 shutil.copyfile("/etc/resolv.conf", chrootdir + "/etc/resolv.conf")
174 except:
175 pass
176
177 globalmounts = get_bind_mounts(chrootdir, bindmounts, mountparent)
178 bind_mount(globalmounts)
179
180 setup_resolv(chrootdir)
181
182 mtab = "/etc/mtab"
183 dstmtab = chrootdir + mtab
184 if not os.path.islink(dstmtab):
185 shutil.copyfile(mtab, dstmtab)
186
187 chroot_lock = os.path.join(chrootdir, ".chroot.lock")
188 chroot_lockfd = open(chroot_lock, "w")
189
190 return globalmounts
191
192def cleanup_chrootenv(chrootdir, bindmounts=None, globalmounts=()):
193 global chroot_lockfd, chroot_lock
194
195 def bind_unmount(chrootmounts):
196 for b in reversed(chrootmounts):
197 msger.verbose("bind_unmount: %s -> %s" % (b.src, b.dest))
198 b.unmount()
199
200 def cleanup_resolv(chrootdir):
201 try:
202 fd = open(chrootdir + "/etc/resolv.conf", "w")
203 fd.truncate(0)
204 fd.close()
205 except:
206 pass
207
208 def kill_processes(chrootdir):
209 import glob
210 for fp in glob.glob("/proc/*/root"):
211 try:
212 if os.readlink(fp) == chrootdir:
213 pid = int(fp.split("/")[2])
214 os.kill(pid, 9)
215 except:
216 pass
217
218 def cleanup_mountdir(chrootdir, bindmounts):
219 if bindmounts == "" or bindmounts == None:
220 return
221 chrootmounts = []
222 for mount in bindmounts.split(";"):
223 if not mount:
224 continue
225
226 srcdst = mount.split(":")
227
228 if len(srcdst) == 1:
229 srcdst.append("none")
230
231 if srcdst[0] == "/":
232 continue
233
234 if srcdst[1] == "" or srcdst[1] == "none":
235 srcdst[1] = srcdst[0]
236
237 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
238 tmpdir = chrootdir + "/" + srcdst[1]
239 if os.path.isdir(tmpdir):
240 if len(os.listdir(tmpdir)) == 0:
241 shutil.rmtree(tmpdir, ignore_errors = True)
242 else:
243 msger.warning("Warning: dir %s isn't empty." % tmpdir)
244
245 chroot_lockfd.close()
246 bind_unmount(globalmounts)
247
248 if not fs_related.my_fuser(chroot_lock):
249 tmpdir = chrootdir + "/parentroot"
250 if os.path.exists(tmpdir) and len(os.listdir(tmpdir)) == 0:
251 shutil.rmtree(tmpdir, ignore_errors = True)
252
253 cleanup_resolv(chrootdir)
254
255 if os.path.exists(chrootdir + "/etc/mtab"):
256 os.unlink(chrootdir + "/etc/mtab")
257
258 kill_processes(chrootdir)
259
260 cleanup_mountdir(chrootdir, bindmounts)
261
262def chroot(chrootdir, bindmounts = None, execute = "/bin/bash"):
263 def mychroot():
264 os.chroot(chrootdir)
265 os.chdir("/")
266
267 if configmgr.chroot['saveto']:
268 savefs = True
269 saveto = configmgr.chroot['saveto']
270 wrnmsg = "Can't save chroot fs for dir %s exists" % saveto
271 if saveto == chrootdir:
272 savefs = False
273 wrnmsg = "Dir %s is being used to chroot" % saveto
274 elif os.path.exists(saveto):
275 if msger.ask("Dir %s already exists, cleanup and continue?" %
276 saveto):
277 shutil.rmtree(saveto, ignore_errors = True)
278 savefs = True
279 else:
280 savefs = False
281
282 if savefs:
283 msger.info("Saving image to directory %s" % saveto)
284 fs_related.makedirs(os.path.dirname(os.path.abspath(saveto)))
285 runner.quiet("cp -af %s %s" % (chrootdir, saveto))
286 devs = ['dev/fd',
287 'dev/stdin',
288 'dev/stdout',
289 'dev/stderr',
290 'etc/mtab']
291 ignlst = [os.path.join(saveto, x) for x in devs]
292 map(os.unlink, filter(os.path.exists, ignlst))
293 else:
294 msger.warning(wrnmsg)
295
296 dev_null = os.open("/dev/null", os.O_WRONLY)
297 files_to_check = ["/bin/bash", "/sbin/init"]
298
299 architecture_found = False
300
301 """ Register statically-linked qemu-arm if it is an ARM fs """
302 qemu_emulator = None
303
304 for ftc in files_to_check:
305 ftc = "%s/%s" % (chrootdir,ftc)
306
307 # Return code of 'file' is "almost always" 0 based on some man pages
308 # so we need to check the file existance first.
309 if not os.path.exists(ftc):
310 continue
311
312 for line in runner.outs(['file', ftc]).splitlines():
313 if 'ARM' in line:
314 qemu_emulator = misc.setup_qemu_emulator(chrootdir, "arm")
315 architecture_found = True
316 break
317
318 if 'Intel' in line:
319 architecture_found = True
320 break
321
322 if architecture_found:
323 break
324
325 os.close(dev_null)
326 if not architecture_found:
327 raise errors.CreatorError("Failed to get architecture from any of the "
328 "following files %s from chroot." \
329 % files_to_check)
330
331 try:
332 msger.info("Launching shell. Exit to continue.\n"
333 "----------------------------------")
334 globalmounts = setup_chrootenv(chrootdir, bindmounts)
335 subprocess.call(execute, preexec_fn = mychroot, shell=True)
336
337 except OSError, err:
338 raise errors.CreatorError("chroot err: %s" % str(err))
339
340 finally:
341 cleanup_chrootenv(chrootdir, bindmounts, globalmounts)
342 if qemu_emulator:
343 os.unlink(chrootdir + qemu_emulator)