3 # Copyright (c) 2009, 2010, 2011 Intel, Inc.
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
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
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.
18 from __future__ import with_statement
24 from mic.utils import misc, errors, runner, fs_related
30 "/proc/sys/fs/binfmt_misc",
40 def cleanup_after_chroot(targettype,imgmount,tmpdir,tmpmnt):
41 if imgmount and targettype == "img":
45 shutil.rmtree(tmpdir, ignore_errors = True)
48 shutil.rmtree(tmpmnt, ignore_errors = True)
50 def check_bind_mounts(chrootdir, bindmounts):
52 for mount in bindmounts.split(";"):
56 srcdst = mount.split(":")
60 if not os.path.isdir(srcdst[0]):
63 if srcdst[1] == "" or srcdst[1] == "none":
66 if srcdst[0] in BIND_MOUNTS or srcdst[0] == '/':
71 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[0]))
73 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
75 tmpdir = chrootdir + "/" + srcdst[1]
76 if os.path.isdir(tmpdir):
77 msger.warning("Warning: dir %s has existed." % tmpdir)
81 def cleanup_mounts(chrootdir):
82 umountcmd = misc.find_binary_path("umount")
83 for point in BIND_MOUNTS:
84 args = [ umountcmd, "-l", chrootdir + point ]
87 args = [ umountcmd, "-l", chrootdir + point ]
90 abs_chrootdir = os.path.abspath(chrootdir)
91 with open('/proc/mounts') as f:
93 if abs_chrootdir in line:
94 point = line.split()[1]
96 if abs_chrootdir == point:
99 args = [ umountcmd, "-l", point ]
100 ret = runner.quiet(args)
102 msger.warning("failed to unmount %s" % point)
107 def setup_chrootenv(chrootdir, bindmounts = None):
108 global chroot_lockfd, chroot_lock
110 def get_bind_mounts(chrootdir, bindmounts):
112 if bindmounts in ("", None):
115 for mount in bindmounts.split(";"):
119 srcdst = mount.split(":")
120 srcdst[0] = os.path.abspath(os.path.expanduser(srcdst[0]))
122 srcdst.append("none")
124 if not os.path.isdir(srcdst[0]):
127 if srcdst[0] in BIND_MOUNTS or srcdst[0] == '/':
128 msger.warning("%s will be mounted by default." % srcdst[0])
131 if srcdst[1] == "" or srcdst[1] == "none":
134 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
135 if os.path.isdir(chrootdir + "/" + srcdst[1]):
136 msger.warning("%s has existed in %s , skip it."\
137 % (srcdst[1], chrootdir))
140 chrootmounts.append(fs_related.BindChrootMount(srcdst[0],
144 """Default bind mounts"""
145 for pt in BIND_MOUNTS:
146 chrootmounts.append(fs_related.BindChrootMount(pt, chrootdir, None))
148 chrootmounts.append(fs_related.BindChrootMount("/",
153 for kernel in os.listdir("/lib/modules"):
154 chrootmounts.append(fs_related.BindChrootMount("/lib/modules/"+kernel,
161 def bind_mount(chrootmounts):
162 for b in chrootmounts:
163 msger.info("bind_mount: %s -> %s" % (b.src, b.dest))
166 def setup_resolv(chrootdir):
167 shutil.copyfile("/etc/resolv.conf", chrootdir + "/etc/resolv.conf")
169 globalmounts = get_bind_mounts(chrootdir, bindmounts)
170 bind_mount(globalmounts)
172 setup_resolv(chrootdir)
175 dstmtab = chrootdir + mtab
176 if not os.path.islink(dstmtab):
177 shutil.copyfile(mtab, dstmtab)
179 chroot_lock = os.path.join(chrootdir, ".chroot.lock")
180 chroot_lockfd = open(chroot_lock, "w")
184 def cleanup_chrootenv(chrootdir, bindmounts = None, globalmounts = []):
185 global chroot_lockfd, chroot_lock
187 def bind_unmount(chrootmounts):
188 chrootmounts.reverse()
189 for b in chrootmounts:
190 msger.info("bind_unmount: %s -> %s" % (b.src, b.dest))
193 def cleanup_resolv(chrootdir):
194 fd = open(chrootdir + "/etc/resolv.conf", "w")
198 def kill_processes(chrootdir):
200 for fp in glob.glob("/proc/*/root"):
202 if os.readlink(fp) == chrootdir:
203 pid = int(fp.split("/")[2])
208 def cleanup_mountdir(chrootdir, bindmounts):
209 if bindmounts == "" or bindmounts == None:
212 for mount in bindmounts.split(";"):
216 srcdst = mount.split(":")
219 srcdst.append("none")
221 if srcdst[1] == "" or srcdst[1] == "none":
222 srcdst[1] = srcdst[0]
224 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
225 tmpdir = chrootdir + "/" + srcdst[1]
226 if os.path.isdir(tmpdir):
227 if len(os.listdir(tmpdir)) == 0:
228 shutil.rmtree(tmpdir, ignore_errors = True)
230 msger.warning("Warning: dir %s isn't empty." % tmpdir)
232 chroot_lockfd.close()
233 bind_unmount(globalmounts)
235 if not fs_related.my_fuser(chroot_lock):
236 tmpdir = chrootdir + "/parentroot"
237 if len(os.listdir(tmpdir)) == 0:
238 shutil.rmtree(tmpdir, ignore_errors = True)
240 cleanup_resolv(chrootdir)
242 if os.path.exists(chrootdir + "/etc/mtab"):
243 os.unlink(chrootdir + "/etc/mtab")
245 kill_processes(chrootdir)
247 cleanup_mountdir(chrootdir, bindmounts)
249 def chroot(chrootdir, bindmounts = None, execute = "/bin/bash"):
254 dev_null = os.open("/dev/null", os.O_WRONLY)
255 files_to_check = ["/bin/bash", "/sbin/init"]
257 architecture_found = False
259 """ Register statically-linked qemu-arm if it is an ARM fs """
262 for ftc in files_to_check:
263 ftc = "%s/%s" % (chrootdir,ftc)
265 # Return code of 'file' is "almost always" 0 based on some man pages
266 # so we need to check the file existance first.
267 if not os.path.exists(ftc):
270 for line in runner.outs(['file', ftc]).splitlines():
272 qemu_emulator = misc.setup_qemu_emulator(chrootdir, "arm")
273 architecture_found = True
277 architecture_found = True
280 if architecture_found:
284 if not architecture_found:
285 raise errors.CreatorError("Failed to get architecture from any of the "
286 "following files %s from chroot." \
290 msger.info("Launching shell. Exit to continue.\n"
291 "----------------------------------")
292 globalmounts = setup_chrootenv(chrootdir, bindmounts)
293 subprocess.call(execute, preexec_fn = mychroot, shell=True)
296 raise errors.CreatorError("chroot err: %s" % str(err))
299 cleanup_chrootenv(chrootdir, bindmounts, globalmounts)
301 os.unlink(chrootdir + qemu_emulator)