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
25 import mic.utils.fs_related as fs_related
26 import mic.utils.misc as misc
27 import mic.utils.errors as errors
34 "/proc/sys/fs/binfmt_misc",
44 def cleanup_after_chroot(targettype,imgmount,tmpdir,tmpmnt):
45 if imgmount and targettype == "img":
49 shutil.rmtree(tmpdir, ignore_errors = True)
52 shutil.rmtree(tmpmnt, ignore_errors = True)
54 def check_bind_mounts(chrootdir, bindmounts):
56 for mount in bindmounts.split(";"):
60 srcdst = mount.split(":")
64 if not os.path.isdir(srcdst[0]):
67 if srcdst[1] == "" or srcdst[1] == "none":
70 if srcdst[0] in BIND_MOUNTS or srcdst[0] == '/':
75 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[0]))
77 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
79 tmpdir = chrootdir + "/" + srcdst[1]
80 if os.path.isdir(tmpdir):
81 msger.warning("Warning: dir %s has existed." % tmpdir)
85 def cleanup_mounts(chrootdir):
86 umountcmd = misc.find_binary_path("umount")
87 for point in BIND_MOUNTS:
88 args = [ umountcmd, "-l", chrootdir + point ]
91 abs_chrootdir = os.path.abspath(chrootdir)
92 with open('/proc/mounts') as f:
94 if abs_chrootdir in line:
95 point = line.split()[1]
97 if abs_chrootdir == point:
100 args = [ umountcmd, "-l", point ]
101 ret = runner.quiet(args)
103 msger.warning("failed to unmount %s" % point)
108 def setup_chrootenv(chrootdir, bindmounts = None):
109 global chroot_lockfd, chroot_lock
111 def get_bind_mounts(chrootdir, bindmounts):
113 if bindmounts in ("", None):
116 for mount in bindmounts.split(";"):
120 srcdst = mount.split(":")
121 srcdst[0] = os.path.abspath(os.path.expanduser(srcdst[0]))
123 srcdst.append("none")
125 if not os.path.isdir(srcdst[0]):
128 if srcdst[0] in BIND_MOUNTS or srcdst[0] == '/':
129 msger.warning("%s will be mounted by default." % srcdst[0])
132 if srcdst[1] == "" or srcdst[1] == "none":
135 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
136 if os.path.isdir(chrootdir + "/" + srcdst[1]):
137 msger.warning("%s has existed in %s , skip it." % (srcdst[1], chrootdir))
140 chrootmounts.append(fs_related.BindChrootMount(srcdst[0], chrootdir, srcdst[1]))
142 """Default bind mounts"""
143 for pt in BIND_MOUNTS:
144 chrootmounts.append(fs_related.BindChrootMount(pt, chrootdir, None))
146 chrootmounts.append(fs_related.BindChrootMount("/", chrootdir, "/parentroot", "ro"))
148 for kernel in os.listdir("/lib/modules"):
149 chrootmounts.append(fs_related.BindChrootMount("/lib/modules/" + kernel, chrootdir, None, "ro"))
153 def bind_mount(chrootmounts):
154 for b in chrootmounts:
155 msger.info("bind_mount: %s -> %s" % (b.src, b.dest))
158 def setup_resolv(chrootdir):
159 shutil.copyfile("/etc/resolv.conf", chrootdir + "/etc/resolv.conf")
161 globalmounts = get_bind_mounts(chrootdir, bindmounts)
162 bind_mount(globalmounts)
164 setup_resolv(chrootdir)
167 dstmtab = chrootdir + mtab
168 if not os.path.islink(dstmtab):
169 shutil.copyfile(mtab, dstmtab)
171 chroot_lock = os.path.join(chrootdir, ".chroot.lock")
172 chroot_lockfd = open(chroot_lock, "w")
176 def cleanup_chrootenv(chrootdir, bindmounts = None, globalmounts = []):
177 global chroot_lockfd, chroot_lock
179 def bind_unmount(chrootmounts):
180 chrootmounts.reverse()
181 for b in chrootmounts:
182 msger.info("bind_unmount: %s -> %s" % (b.src, b.dest))
185 def cleanup_resolv(chrootdir):
186 fd = open(chrootdir + "/etc/resolv.conf", "w")
190 def kill_processes(chrootdir):
192 for fp in glob.glob("/proc/*/root"):
194 if os.readlink(fp) == chrootdir:
195 pid = int(fp.split("/")[2])
200 def cleanup_mountdir(chrootdir, bindmounts):
201 if bindmounts == "" or bindmounts == None:
204 for mount in bindmounts.split(";"):
208 srcdst = mount.split(":")
211 srcdst.append("none")
213 if srcdst[1] == "" or srcdst[1] == "none":
214 srcdst[1] = srcdst[0]
216 srcdst[1] = os.path.abspath(os.path.expanduser(srcdst[1]))
217 tmpdir = chrootdir + "/" + srcdst[1]
218 if os.path.isdir(tmpdir):
219 if len(os.listdir(tmpdir)) == 0:
220 shutil.rmtree(tmpdir, ignore_errors = True)
222 msger.warning("Warning: dir %s isn't empty." % tmpdir)
224 chroot_lockfd.close()
225 bind_unmount(globalmounts)
227 if not fs_related.my_fuser(chroot_lock):
228 tmpdir = chrootdir + "/parentroot"
229 if len(os.listdir(tmpdir)) == 0:
230 shutil.rmtree(tmpdir, ignore_errors = True)
232 cleanup_resolv(chrootdir)
234 if os.path.exists(chrootdir + "/etc/mtab"):
235 os.unlink(chrootdir + "/etc/mtab")
237 kill_processes(chrootdir)
239 cleanup_mountdir(chrootdir, bindmounts)
241 def chroot(chrootdir, bindmounts = None, execute = "/bin/bash"):
246 dev_null = os.open("/dev/null", os.O_WRONLY)
247 files_to_check = ["/bin/bash", "/sbin/init"]
249 architecture_found = False
251 """ Register statically-linked qemu-arm if it is an ARM fs """
254 for ftc in files_to_check:
255 ftc = "%s/%s" % (chrootdir,ftc)
257 # Return code of 'file' is "almost always" 0 based on some man pages
258 # so we need to check the file existance first.
259 if not os.path.exists(ftc):
262 filecmd = misc.find_binary_path("file")
264 for line in subprocess.Popen([filecmd, ftc],
265 stdout=subprocess.PIPE,
266 stderr=dev_null).communicate()[0].strip().splitlines():
268 qemu_emulator = misc.setup_qemu_emulator(chrootdir, "arm")
269 architecture_found = True
273 architecture_found = True
276 if architecture_found:
280 if not architecture_found:
281 raise errors.CreatorError("Failed to get architecture from any of the following files %s from chroot." % files_to_check)
284 msger.info("Launching shell. Exit to continue.\n----------------------------------")
285 globalmounts = setup_chrootenv(chrootdir, bindmounts)
286 subprocess.call(execute, preexec_fn = mychroot, shell=True)
288 except OSError, (err, msg):
289 raise errors.CreatorError("Failed to chroot: %s" % msg)
292 cleanup_chrootenv(chrootdir, bindmounts, globalmounts)
294 os.unlink(chrootdir + qemu_emulator)