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.conf import configmgr
25 from mic.utils import misc, errors, runner, fs_related
27 #####################################################################
29 #####################################################################
31 chroot_bindmounts = None
36 "/proc/sys/fs/binfmt_misc",
45 #####################################################################
47 #####################################################################
49 def get_bindmounts(chrootdir, bindmounts):
50 global chroot_bindmounts
53 return chroot_bindmounts
56 bindmounts = bindmounts or ""
58 for mount in bindmounts.split(";"):
62 srcdst = mount.split(":")
63 srcdst[0] = os.path.abspath(os.path.expanduser(srcdst[0]))
67 # if some bindmount is not existed, but it's created inside
68 # chroot, this is not expected
69 if not os.path.exists(srcdst[0]):
70 os.makedirs(srcdst[0])
72 if not os.path.isdir(srcdst[0]):
75 if srcdst[0] in BIND_MOUNTS or srcdst[0] == '/':
76 msger.verbose("%s will be mounted by default." % srcdst[0])
79 if srcdst[1] == "" or srcdst[1] == "none":
82 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
83 if os.path.isdir(chrootdir + "/" + srcdst[1]):
84 msger.warning("%s has existed in %s , skip it."\
85 % (srcdst[1], chrootdir))
88 chrootmounts.append(fs_related.BindChrootMount(srcdst[0],
92 """Default bind mounts"""
93 for pt in BIND_MOUNTS:
94 if not os.path.exists(pt):
96 chrootmounts.append(fs_related.BindChrootMount(pt,
100 for kernel in os.listdir("/lib/modules"):
101 chrootmounts.append(fs_related.BindChrootMount(
102 "/lib/modules/"+kernel,
106 chroot_bindmounts = chrootmounts
107 return chroot_bindmounts
109 #####################################################################
110 ### SETUP CHROOT ENVIRONMENT
111 #####################################################################
113 def bind_mount(chrootmounts):
114 for b in chrootmounts:
115 msger.verbose("bind_mount: %s -> %s" % (b.src, b.dest))
118 def setup_resolv(chrootdir):
120 shutil.copyfile("/etc/resolv.conf", chrootdir + "/etc/resolv.conf")
124 def setup_mtab(chrootdir):
126 dstmtab = chrootdir + mtab
127 if not os.path.islink(dstmtab):
128 shutil.copyfile(mtab, dstmtab)
130 def setup_chrootenv(chrootdir, bindmounts = None):
132 bind_mount(get_bindmounts(chrootdir, bindmounts))
134 setup_resolv(chrootdir)
136 setup_mtab(chrootdir)
139 chroot_lock = os.path.join(chrootdir, ".chroot.lock")
140 chroot_lockfd = open(chroot_lock, "w")
144 ######################################################################
145 ### CLEANUP CHROOT ENVIRONMENT
146 ######################################################################
148 def bind_unmount(chrootmounts):
149 for b in reversed(chrootmounts):
150 msger.verbose("bind_unmount: %s -> %s" % (b.src, b.dest))
153 def cleanup_resolv(chrootdir):
155 fd = open(chrootdir + "/etc/resolv.conf", "w")
161 def kill_processes(chrootdir):
163 for fp in glob.glob("/proc/*/root"):
165 if os.readlink(fp) == chrootdir:
166 pid = int(fp.split("/")[2])
171 def cleanup_mtab(chrootdir):
172 if os.path.exists(chrootdir + "/etc/mtab"):
173 os.unlink(chrootdir + "/etc/mtab")
175 def cleanup_mounts(chrootdir):
176 umountcmd = misc.find_binary_path("umount")
177 mounts = open('/proc/mounts').readlines()
178 for line in reversed(mounts):
179 if chrootdir not in line:
182 point = line.split()[1]
184 # '/' to avoid common name prefix
185 if chrootdir == point or point.startswith(chrootdir + '/'):
186 args = [ umountcmd, "-l", point ]
187 ret = runner.quiet(args)
189 msger.warning("failed to unmount %s" % point)
190 if os.path.isdir(point) and len(os.listdir(point)) == 0:
193 msger.warning("%s is not directory or is not empty" % point)
195 def cleanup_chrootenv(chrootdir, bindmounts=None, globalmounts=()):
197 chroot_lockfd.close()
199 kill_processes(chrootdir)
201 cleanup_mtab(chrootdir)
203 cleanup_resolv(chrootdir)
205 bind_unmount(get_bindmounts(chrootdir, bindmounts))
207 cleanup_mounts(chrootdir)
211 #####################################################################
213 #####################################################################
215 def cleanup_after_chroot(targettype, imgmount, tmpdir, tmpmnt):
216 if imgmount and targettype == "img":
220 shutil.rmtree(tmpdir, ignore_errors = True)
223 shutil.rmtree(tmpmnt, ignore_errors = True)
225 def chroot(chrootdir, bindmounts = None, execute = "/bin/bash"):
230 if configmgr.chroot['saveto']:
232 saveto = configmgr.chroot['saveto']
233 wrnmsg = "Can't save chroot fs for dir %s exists" % saveto
234 if saveto == chrootdir:
236 wrnmsg = "Dir %s is being used to chroot" % saveto
237 elif os.path.exists(saveto):
238 if msger.ask("Dir %s already exists, cleanup and continue?" %
240 shutil.rmtree(saveto, ignore_errors = True)
246 msger.info("Saving image to directory %s" % saveto)
247 fs_related.makedirs(os.path.dirname(os.path.abspath(saveto)))
248 runner.quiet("cp -af %s %s" % (chrootdir, saveto))
254 ignlst = [os.path.join(saveto, x) for x in devs]
255 map(os.unlink, filter(os.path.exists, ignlst))
257 msger.warning(wrnmsg)
259 files_to_check = ["/bin/bash", "/sbin/init"]
261 architecture_found = False
263 """ Register statically-linked qemu-arm if it is an ARM fs """
266 for ftc in files_to_check:
267 ftc = "%s/%s" % (chrootdir,ftc)
269 # Return code of 'file' is "almost always" 0 based on some man pages
270 # so we need to check the file existance first.
271 if not os.path.exists(ftc):
274 for line in runner.outs(['file', ftc]).splitlines():
276 qemu_emulator = misc.setup_qemu_emulator(chrootdir, "arm")
277 architecture_found = True
281 architecture_found = True
284 if architecture_found:
287 if not architecture_found:
288 raise errors.CreatorError("Failed to get architecture from any of the "
289 "following files %s from chroot." \
293 msger.info("Launching shell. Exit to continue.\n"
294 "----------------------------------")
295 globalmounts = setup_chrootenv(chrootdir, bindmounts)
296 subprocess.call(execute, preexec_fn = mychroot, shell=True)
299 raise errors.CreatorError("chroot err: %s" % str(err))
302 cleanup_chrootenv(chrootdir, bindmounts, globalmounts)
304 os.unlink(chrootdir + qemu_emulator)