3 # Copyright 2009, 2010, 2011 Intel, Inc.
5 # This copyrighted material is made available to anyone wishing to use, modify,
6 # copy, or redistribute it subject to the terms and conditions of the GNU
7 # General Public License v.2. This program is distributed in the hope that it
8 # will be useful, but WITHOUT ANY WARRANTY expressed or implied, including the
9 # implied warranties of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 # See the GNU General Public License for more details.
12 # You should have received a copy of the GNU General Public License along with
13 # this program; if not, write to the Free Software Foundation, Inc., 51
14 # Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. Any Red Hat
15 # trademarks that are incorporated in the source code or documentation are not
16 # subject to the GNU General Public License and may only be used or replicated
17 # with the express permission of Red Hat, Inc.
20 from __future__ import with_statement
26 from mic.utils import misc, errors, runner, fs_related
32 "/proc/sys/fs/binfmt_misc",
42 def cleanup_after_chroot(targettype,imgmount,tmpdir,tmpmnt):
43 if imgmount and targettype == "img":
47 shutil.rmtree(tmpdir, ignore_errors = True)
50 shutil.rmtree(tmpmnt, ignore_errors = True)
52 def check_bind_mounts(chrootdir, bindmounts):
54 for mount in bindmounts.split(";"):
58 srcdst = mount.split(":")
62 if not os.path.isdir(srcdst[0]):
65 if srcdst[1] == "" or srcdst[1] == "none":
68 if srcdst[0] in BIND_MOUNTS or srcdst[0] == '/':
73 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[0]))
75 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
77 tmpdir = chrootdir + "/" + srcdst[1]
78 if os.path.isdir(tmpdir):
79 msger.warning("Warning: dir %s has existed." % tmpdir)
83 def cleanup_mounts(chrootdir):
84 umountcmd = misc.find_binary_path("umount")
85 for point in BIND_MOUNTS:
86 args = [ umountcmd, "-l", chrootdir + point ]
89 abs_chrootdir = os.path.abspath(chrootdir)
90 with open('/proc/mounts') as f:
92 if abs_chrootdir in line:
93 point = line.split()[1]
95 if abs_chrootdir == point:
98 args = [ umountcmd, "-l", point ]
99 ret = runner.quiet(args)
101 msger.warning("failed to unmount %s" % point)
106 def setup_chrootenv(chrootdir, bindmounts = None):
107 global chroot_lockfd, chroot_lock
109 def get_bind_mounts(chrootdir, bindmounts):
111 if bindmounts in ("", None):
114 for mount in bindmounts.split(";"):
118 srcdst = mount.split(":")
119 srcdst[0] = os.path.abspath(os.path.expanduser(srcdst[0]))
121 srcdst.append("none")
123 if not os.path.isdir(srcdst[0]):
126 if srcdst[0] in BIND_MOUNTS or srcdst[0] == '/':
127 msger.warning("%s will be mounted by default." % srcdst[0])
130 if srcdst[1] == "" or srcdst[1] == "none":
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." % (srcdst[1], chrootdir))
138 chrootmounts.append(fs_related.BindChrootMount(srcdst[0], chrootdir, srcdst[1]))
140 """Default bind mounts"""
141 for pt in BIND_MOUNTS:
142 chrootmounts.append(fs_related.BindChrootMount(pt, chrootdir, None))
144 chrootmounts.append(fs_related.BindChrootMount("/", chrootdir, "/parentroot", "ro"))
146 for kernel in os.listdir("/lib/modules"):
147 chrootmounts.append(fs_related.BindChrootMount("/lib/modules/" + kernel, chrootdir, None, "ro"))
151 def bind_mount(chrootmounts):
152 for b in chrootmounts:
153 msger.info("bind_mount: %s -> %s" % (b.src, b.dest))
156 def setup_resolv(chrootdir):
157 shutil.copyfile("/etc/resolv.conf", chrootdir + "/etc/resolv.conf")
159 globalmounts = get_bind_mounts(chrootdir, bindmounts)
160 bind_mount(globalmounts)
162 setup_resolv(chrootdir)
165 dstmtab = chrootdir + mtab
166 if not os.path.islink(dstmtab):
167 shutil.copyfile(mtab, dstmtab)
169 chroot_lock = os.path.join(chrootdir, ".chroot.lock")
170 chroot_lockfd = open(chroot_lock, "w")
174 def cleanup_chrootenv(chrootdir, bindmounts = None, globalmounts = []):
175 global chroot_lockfd, chroot_lock
177 def bind_unmount(chrootmounts):
178 chrootmounts.reverse()
179 for b in chrootmounts:
180 msger.info("bind_unmount: %s -> %s" % (b.src, b.dest))
183 def cleanup_resolv(chrootdir):
184 fd = open(chrootdir + "/etc/resolv.conf", "w")
188 def kill_processes(chrootdir):
190 for fp in glob.glob("/proc/*/root"):
192 if os.readlink(fp) == chrootdir:
193 pid = int(fp.split("/")[2])
198 def cleanup_mountdir(chrootdir, bindmounts):
199 if bindmounts == "" or bindmounts == None:
202 for mount in bindmounts.split(";"):
206 srcdst = mount.split(":")
209 srcdst.append("none")
211 if srcdst[1] == "" or srcdst[1] == "none":
212 srcdst[1] = srcdst[0]
214 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
215 tmpdir = chrootdir + "/" + srcdst[1]
216 if os.path.isdir(tmpdir):
217 if len(os.listdir(tmpdir)) == 0:
218 shutil.rmtree(tmpdir, ignore_errors = True)
220 msger.warning("Warning: dir %s isn't empty." % tmpdir)
222 chroot_lockfd.close()
223 bind_unmount(globalmounts)
225 if not fs_related.my_fuser(chroot_lock):
226 tmpdir = chrootdir + "/parentroot"
227 if len(os.listdir(tmpdir)) == 0:
228 shutil.rmtree(tmpdir, ignore_errors = True)
230 cleanup_resolv(chrootdir)
232 if os.path.exists(chrootdir + "/etc/mtab"):
233 os.unlink(chrootdir + "/etc/mtab")
235 kill_processes(chrootdir)
237 cleanup_mountdir(chrootdir, bindmounts)
239 def chroot(chrootdir, bindmounts = None, execute = "/bin/bash"):
244 dev_null = os.open("/dev/null", os.O_WRONLY)
245 files_to_check = ["/bin/bash", "/sbin/init"]
247 architecture_found = False
249 """ Register statically-linked qemu-arm if it is an ARM fs """
252 for ftc in files_to_check:
253 ftc = "%s/%s" % (chrootdir,ftc)
255 # Return code of 'file' is "almost always" 0 based on some man pages
256 # so we need to check the file existance first.
257 if not os.path.exists(ftc):
260 for line in runner.outs(['file', ftc]).splitlines():
262 qemu_emulator = misc.setup_qemu_emulator(chrootdir, "arm")
263 architecture_found = True
267 architecture_found = True
270 if architecture_found:
274 if not architecture_found:
275 raise errors.CreatorError("Failed to get architecture from any of the following files %s from chroot." % files_to_check)
278 msger.info("Launching shell. Exit to continue.\n----------------------------------")
279 globalmounts = setup_chrootenv(chrootdir, bindmounts)
280 subprocess.call(execute, preexec_fn = mychroot, shell=True)
283 raise errors.CreatorError("chroot err: %s" % str(err))
286 cleanup_chrootenv(chrootdir, bindmounts, globalmounts)
288 os.unlink(chrootdir + qemu_emulator)