+ echo '====== automated-ec2-builds [/tmp/automated-ec2-builds] ======' ====== automated-ec2-builds [/tmp/automated-ec2-builds] ====== + cd /tmp/automated-ec2-builds + bzr info Standalone tree (format: 2a) Location: branch root: . Related branches: parent branch: http://bazaar.launchpad.net/~ubuntu-on-ec2/vmbuilder/automated-ec2-builds/ + bzr version-info revision-id: ben.howard@ubuntu.com-20140530234631-rlxwnx16v3w0ho38 date: 2014-05-30 17:46:31 -0600 build-date: 2014-06-06 19:45:30 +0000 revno: 632 branch-nick: automated-ec2-builds + bzr log -p -r-1 ------------------------------------------------------------ revno: 632 committer: Ben Howard branch nick: trunk timestamp: Fri 2014-05-30 17:46:31 -0600 message: Modified license.py to produce a very satisfying, light evening read for budding laywers and those trying to torment them. The tool now outputs a HTML file which contains all the license that it can find, after downloading the source files. At nearly 231 pages for Precise, the report should satisfy most laywers. diff: === modified file 'misc/license.py' --- misc/license.py 2013-11-21 18:35:13 +0000 +++ misc/license.py 2014-05-30 23:46:31 +0000 @@ -2,7 +2,13 @@ # # Extract license information from manifest file # -# +# This script is dead simple -- using the pull-lp-source tool, it +# iterates over a manifest and then downloads the source. Then it +# uses the 'license-check' tool to extract the information. +# +# + +import __future__ import argparse import csv import logging as LOG @@ -15,6 +21,14 @@ LOG.basicConfig(format='%(levelname)s:%(message)s', level=LOG.DEBUG) +# Populate the system licenses we know about +system_licenses = {} +common_license_d = "/usr/share/common-licenses" +for root, dirs, files in os.walk(common_license_d): + for f in files: + LOG.info("Added system license: %s" % f) + system_licenses[f] = "%s/%s" % (common_license_d, f) + ## Shamelessly stolen from cloud-init def subp(args, data=None, rcs=None, env=None, capture=True, shell=False, logstring=False): @@ -57,7 +71,145 @@ err = '' return (out, err) -def parse_manifest(name_f, dump_f): +def _normalize_license(lic): + """ + Take the long name and map to the canonical form, i.e. + GPL (v1 or later) to GPL + """ + version = None + try: + version = re.search(r".*(\(.*\))", lic).group(1) + LOG.debug("Reduced license version to: %s" % version) + except: + LOG.info("Did not find license version for %s" % lic) + + # Get just the version + name = lic.split()[0] + if version: + version = re.sub(r'(\(|\)|v)', '', version) + version = version.split()[0] + + # v1 are not shown as "-1" + if version: + if version == "1": + version = None + elif ".0" in version: + version = version.split('.0')[0] + + # Handle short names, i.e. GPL + nam_ver = "%s-%s" % (name, version) + if not version: + nam_ver = name + + LOG.debug("Looking for '%s' [%s] in system licenses" % (lic, nam_ver)) + if nam_ver in system_licenses: + LOG.debug(" found %s as matching license" % nam_ver) + return (nam_ver, system_licenses[nam_ver]) + else: + LOG.debug(" did not find %s in system licenses" % nam_ver) + + return (None, None) + +def _stripper(string): + # Match on explicit licences + if re.search("\/usr\/share\/common-licenses\/([A-z].*)", string): + string = re.search("\/usr\/share\/common-licenses\/(.*)", string).group(1) + + # Reg-exes to try and find stuff + licenses = { + "(the.BSD.license|BSD.Copyright)": 'BSD', + "(BSD-1|BSD \(2 clause\))": 'BSD (2 clause)', + "(BSD-3|BSD \(3 clause\))": 'BSD (3 clause)', + "(BSD-4|BSD \(4 clause\))": 'BSD (4 clause)', + "BSD with advertising": 'BSD Advertising', + "GPL \(unversioned/unknown version\)": 'GPL', + "GFDL \(unversioned/unknown version\)": 'GFDL', + "GFDL-NIV \(unversioned/unknown version\)": 'GFDL-NIV', + "(GFDL-NIV \(v1\)|GFDL-1)": 'GFDL (v1)', + "(GFDL-NIV \(v2\)|GFDL-2)": 'GFDL (v2)', + "(GFDL-NIV \(v3\)|GFDL-3)": 'GFDL (v3)', + "(GFDL-NIV \(v1 or later\)|GNU GFDL, Version 2 or later|GFDL-1\+|GFDL \(1,\))": + 'GFDL-NIV (v1 or later)', + "(GFDL-NIV \(v2 or later\)|GNU GFDL, Version 2 or later|GFDL-2\+|GFDL \(2,\))": + 'GFDL-NIV (v2 or later)', + "(GFDL-NIV \(v3 or later\)|GNU GFDL, Version 3 or later|GFDL-3\+|GFDL \(3,\))": + 'GFDL-NIV (v3 or later)', + "(GFDL \(v1\)|GFDL-1)": 'GFDL (v1)', + "(GFDL \(v2\)|GFDL-2)": 'GFDL (v2)', + "(GFDL \(v3\)|GFDL-3)": 'GFDL (v3)', + "(GFDL \(v1.2 or later\)|GNU GFDL, Version 1.2 or later|GFDL-1.2\+|GFDL \(1.2,\)|GNU Free Documentation License.*1.2.*)": + 'GFDL (v1 or later)', + "(GFDL \(v1 or later\)|GNU GFDL, Version 1 or later|GFDL-1\+|GFDL \(1,\))": + 'GFDL (v1 or later)', + "(GFDL \(v2 or later\)|GNU GFDL, Version 2 or later|GFDL-2\+|GFDL \(2,\))": + 'GFDL (v2 or later)', + "(GFDL \(v3 or later\)|GNU GFDL, Version 3 or later|GFDL-3\+|GFDL \(3,\))": + 'GFDL (v3 or later)', + "(GPL \(v1\)|GPL-1|GNU General Public License version 1)": 'GPL (v1)', + "(GPL \(v2\)|GPL-2|GNU General Public License version 2)": 'GPL (v2)', + "(GPL \(v3\)|GPL-3|GNU General Public License version 3)": 'GPL (v3)', + "(GPL \(v1 or later\)|GNU GPL, Version 2 or later|GNU General Public License version 1 or later|GNU General Public License version 1, or any later version|GPL-1\+|GPL \(1\,\)|GPL v1 or above|GNU General Public License, either version 1 or.*any newer version|GNU General Public License \(GPL\)\, version 1\, or.*at your option any later version)": + 'GPL (v1 or later)', + "(GPL \(v2 or later\)|GNU GPL, Version 2 or later|GNU General Public License version 2 or later|GNU General Public License version 2, or any later version|GPL-2\+|GPL \(2\,\)|GPL v2 or above|GNU General Public License, either version 2 or.*any newer version|GNU General Public License \(GPL\)\, version 2\, or.*at your option any later version)": + 'GPL (v2 or later)', + "(GPL \(v3 or later\)|GNU GPL, Version 3 or later|GNU General Public License version 3 or later|GNU General Public License version 3, or any later version|GPL-3\+|GPL \(3\,\)|GPL v3 or above|GNU General Public License, either version 3 or.*any newer version|GNU General Public License \(GPL\)\, version 3\, or.*at your option any later version)": + 'GPL (v3 or later)', + "(LGPL \(v2 or later\)|LGP \(2\)|LGPL \(2,\)|GNU LESSER GENERAL PUBLIC LICENSE.*Version 2)": + 'LGPL (v2 or later)', + "(LGPL \(v2.1 or later\)|LGPL \(v2.1\)|LGPL \(2.1,\)|GNU LESSER GENERAL PUBLIC LICENSE.*Version 2.1)": + 'LGPL (v2.1 or later)', + "(LGPL \(v3.0 or later\)|LGPL \(v3.0\)|LGPL \(3,\)|GNU LESSER GENERAL PUBLIC LICENSE.*Version 3)": + 'LGPL (v3.0 or later)', + "(LDP GENERAL PUBLIC LICENSE|LDP General Public License)": "LDPL", + "(MIT|M.I.T|MIT/X11 \(BSD like\))": 'MIT/X11 (BSD like)', + "(MIT License \(Expat\)|EXPAT)": 'EXPAT', + "Apache": 'Apache', + "CC-BY": 'Creative Commons Attribution', + "(CC0|Creative Commons Zero)": 'CC0', + "(CDDL|Common Development and Distribution)": 'CCDL', + "(CPL|IBM Common Public License)": "CPL", + "(EFL|Eiffel Forum License)": 'EFL', + "(Artistic|Artistic-1)": 'Artistic', + "ISC": 'ISC', + "WTFPL": "WTFPL", + "(MPL \(v2.0\)|Mozilla Public License 2.0)": "MPL (v2.0)", + "(MPL \(v1.0\)|Mozilla Public License 1.0)": "MPL (v1.0)", + "(MPL \(v1.1\)|Mozilla Public License 1.1)": "MPL (v1.1)", + "Python License": "Python", + "QPL": 'QPL', + "Zope Public License": 'Zope', + } + + generic_licenses = { + "GPL": "GPL", + "BSD": "BSD", + "Public Domain": "Public Domain", + "(\*No copyright\* UNKNOWN|\*No copyright\* Public domain)": "Copy-left", + "Copying and distribution of this file, with or without modification, are permitted in any medium without royalty provided the copyright notice and this notice are preserved.": "Copy-left", + "You may freely.*binary or source.*": "Copy-left", + "Public Domain|Copyright\: public-domain": 'Public Domain', + "Read the file copyright in the main directory of this package for copyright information.": "Parent-license", + + } + + string = string.replace('\n', ' ').strip() + matched = [] + for k, v in licenses.items(): + if re.search(k, string): + matched.append(v) + + if len(matched) == 0: + for k, v in generic_licenses.items(): + if re.search(k, string): + matched.append(v) + + if len(matched) == 0: + return ([], True) + + return ([x for x in set(matched)], False) + + +def parse_manifest(name_f, dump_f, dump_reuse, download=True): """ Iterate over manifest of ' ' and fetch the files via 'pull-lp-source' @@ -67,113 +219,282 @@ raise Exception("No such file %s" % name_f) pkgs = [] + pkgs_names = [] with open(name_f, 'r') as f: for meta in f.readlines(): (pkg, version) = meta.split() pkgs.append((pkg, version)) + pkgs_names.append(pkg) LOG.info("Found %s packages" % len(pkgs)) + # Populate system licenses + licenses = {'summary': [], + 'system_licenses': system_licenses, + 'pkg_non_standard_licenses': {}, + 'pkg_standard_licenses': {}, + } + for license in system_licenses: + licenses['pkg_standard_licenses'][license] = [] + # Move the directory current_d = os.getcwd() - tmp_d = tempfile.mkdtemp(prefix="source.", dir=current_d) - os.chdir(tmp_d) + existing_paths = [] + my_path = None + if dump_reuse: + os.chdir(dump_reuse) + my_path = dump_reuse + # Populate the existing + for root, dirs, _ in os.walk(dump_reuse, topdown=True): + for dir_n in dirs: + existing_paths.append(dir_n) + else: + tmp_d = tempfile.mkdtemp(prefix="source.", dir=current_d) + os.chdir(tmp_d) + my_path = dump_reuse + + def is_existing(pkg): + """Determine if pkg and version have been downloaded already""" + for p in existing_paths: + if pkg in p: + LOG.info("Already downloaded source for %s" % pkg) + return True + return False # Download the packages lp_cmd = "pull-lp-source" for pkg_meta in pkgs: (pkg, version) = pkg_meta cmd = [lp_cmd, pkg, version] - LOG.info("Fetching %s %s" % (pkg, version)) - (out, _err) = subp(cmd) - - - licenses = {'summary': []} + + if not is_existing(pkg) and download: + LOG.info("Fetching %s %s" % (pkg, version)) + (out, _err) = subp(cmd, rcs=[0, 1]) + + # Now process them for root, dirs, _ in os.walk(os.getcwd(), topdown=True): for name in dirs: name_d = "%s" % os.path.join(root, name) - if not re.search(r'.*\/debian$', name_d): - continue - - if re.search(r'.*(patches|\.pc|packages|tests)\/debian$', name_d): - continue - - LOG.info("Processing %s" % name_d) + if re.search(r'.*(patches|\.pc|packages|tests|debian\-example)', name_d) or \ + re.search(r'.*debian\/(patches|\.pc|packages|tests).*', name_d): + continue control = None copyrights = [] for sr, sd, sf in os.walk(name_d): for sfn in sf: candidate_f = os.path.join(sr, sfn) - if re.match('.*\/control$', candidate_f): + + if re.search(r'.*(.git.*|.bzr.*|.py|.sh|.c|.h|.patch|CVS)$', + candidate_f) or \ + re.search(r'.*\/licenses\/.*', candidate_f): + continue + elif re.match('.*\/control$', candidate_f): control = candidate_f - elif re.match('.*copyright$', candidate_f): - copyrights.append(candidate_f) - elif re.match('.*copyrights\.in$', candidate_f): + elif re.match('.*(copyright.*|LICENSE.*|WHENCE|COPYING.*|copying.*|license.*)', candidate_f): copyrights.append(candidate_f) - sub_l = {} sub_p = [] + sub_b = [] + sub_a = [] src_p = None if not control: continue - + with open(control, 'r') as f: for line in f.readlines(): if re.match('^Source:.*', line): src_p = line.split(':')[-1].strip() if re.match('^Package:.*', line): - sub_p.append(line.split(':')[-1].strip()) + _pkg = line.split(':')[-1].strip() + if _pkg in pkgs_names: + sub_p.append(_pkg) + else: + sub_b.append(_pkg) + sub_a.append(_pkg) + + if src_p not in licenses: + licenses[src_p] = {'licenses': {}, 'standard_licenses': {}} for copyright in copyrights: - cmd = ["licensecheck", "--lines=300", copyright] + cmd = ["licensecheck", "--lines=500", copyright] (out, _err) = subp(cmd) - out = str(out, encoding='utf-8') - cc = (out.strip()).split('copyright: ')[-1] - cc = cc.replace('/usr/share/common-licenses/','') - ccn = "debian/%s" % copyright.split('debian/')[1] - sub_l[ccn] = cc + out = str(out) #, encoding='utf-8') + cc = (out.strip()).split(': ')[-1] + ccn = copyright + _found, _unknown = _stripper(cc) - if "UNKNOWN" in cc: + if _unknown: with open(copyright, 'r') as f: - reg_ex_l = [] - for line in f.readlines(): - if re.search( - r"(?<=\/usr\/share\/common-licenses\/).*", - line): - reg = re.search( - r"(?<=\/usr\/share\/common-licenses\/).*", - line).group(0) - - if reg not in reg_ex_l: - reg_ex_l.append(reg) - - # Really, really shoddy...but oh well - if "Copyright: public-domain" and \ - "Public Domain" not in reg_ex_l: - reg_ex_l.append("Public Domain") - - if "M.I.T." in line and "MIT" not in reg_ex_l: - reg_ex_l.append("MIT") - - if "A full copy of the GNU GPL can be found in /usr/share/common-licenses" \ - in line and "GPL" not in reg_ex_l: - reg_ex_l.append("Public domain GPL (unversioned/unknown version)") - - if len(reg_ex_l) > 0: - sub_l[ccn] = " ".join(reg_ex_l) - - licenses[src_p] = {'packages': sub_p, - 'licenses': sub_l} + _found, _unknown = _stripper(f.read()) + + if _unknown: + _found = ["UNKNOWN"] + + for lic in _found: + sys_license, sys_path = _normalize_license(lic) + + if not sys_license and not sys_path: + if ccn not in licenses[src_p]['licenses']: + licenses[src_p]['licenses'][ccn] = [] + licenses[src_p]['licenses'][ccn].extend(_found) + licenses[src_p]['licenses'][ccn] = [ + x for x in set(licenses[src_p]['licenses'][ccn])] + + if src_p not in licenses['pkg_non_standard_licenses']: + licenses['pkg_non_standard_licenses'][src_p] = {} + + for k, v in licenses[src_p]['licenses'].items(): + licenses['pkg_non_standard_licenses'][src_p][k] = v + + else: + if ccn not in licenses[src_p]['standard_licenses']: + licenses[src_p]['standard_licenses'][ccn] = [] + licenses[src_p]['standard_licenses'][ccn].append( + sys_license) + licenses[src_p]['standard_licenses'][ccn] = [ + x for x in set(licenses[src_p]['standard_licenses'][ccn])] + + licenses['pkg_standard_licenses'][sys_license].extend(sub_p) + licenses['pkg_standard_licenses'][sys_license] = \ + sorted([x for x in set(\ + licenses['pkg_standard_licenses'][sys_license] + )]) + + licenses[src_p]['pkgs_installed'] = sub_p + licenses[src_p]['pkgs_built_from_source'] = sub_a + + if len(sub_b) > 0: + licenses[src_p]['pkgs_not_installed'] = sub_b os.chdir(current_d) + if '.json' not in dump_f: + dump_f += ".json" with open(dump_f, 'w') as f: f.write(json.dumps(licenses, indent=4)) + return licenses + +def license_html(licenses, manifest, dump_f): + """ + This generates a standard HTML file with the list of licenseses, + the text and the package name + """ + + text = """ + + + +Title of the document + + + +

License information for Ubuntu Server

+

The following packages and versions are covered by this +document.

+ +

Ubuntu is covered by the following polices

+Canonical Intellecutal Property Rights +Ubuntu Legal + +

Disclaimer: The author(s) of this tool no representation or warranty as to the accuracy or completeness of this list or the information it represents, and we expressly disclaim any implied warranties to the fullest extent permissible at law. We accept no liability for any damage or loss arising form your use or reliance on the list. All use of the list is subject to these terms.

+ +

This report was generated using tool which relies on the meta-data for each file. The user of this report is responabile for verifying the accuracy of this list.

+ +

Package list

+

This document discloses the license information for the following packages and version

+ +
    +""" + + # Copy in the manifest + LOG.info("Adding manifest to HTML") + with open(manifest, 'r') as f: + for line in f.readlines(): + text += "
  • %s
  • " % line.strip() + text += "\n
\n" + text += """ +
+

Standard System Licenses

+

These are the standard licenses, which use Debian standard +system licenses.

+ +""" + LOG.info("Processing standard licenses") + for std_license in licenses['pkg_standard_licenses']: + pkgs = licenses['pkg_standard_licenses'][std_license] + npkgs = len(pkgs) + if npkgs == 0: + LOG.info(" Skipping %s (no pkgs)" % std_license) + continue + + LOG.info(" Adding %s" % std_license) + LOG.info(" Packages licensed %s" % npkgs) + license_f = "%s/%s" % (common_license_d, std_license) + license_txt = None + with open(license_f, 'r') as f: + license_txt = f.read() + LOG.info(" Read %s" % license_f) + + text += """ +

License: %s

+

The following packages are covered under this license

+
    +""" % std_license + + for pkg in pkgs: + text += "
  • %s
  • \n" % pkg.strip() + + text += """ +
+

License Text:

+
+%s
+    
+""" % license_txt + + text += """ +
+

Non-standard Licenses

+

These license are free and open licenses, but are either modified, +or are licenses that allow modification to their terms.

+""" + + for pkg in licenses['pkg_non_standard_licenses']: + text += "

Package: %s

" % pkg + LOG.info("Adding licenses for %s" % pkg) + pkg_license = licenses['pkg_non_standard_licenses'][pkg] + for nstd_l in pkg_license: + license_txt = None + LOG.info(" Adding %s as text" % nstd_l) + + try: + with open(nstd_l, 'r') as f: + license_txt = f.read() + except: + continue + + text += """ +

License(s): %s"

+
+%s
+
""" % (",".join(pkg_license), license_txt) + + text += """ + + +""" + + if ".html" not in dump_f: + dump_f += ".html" + + with open(dump_f, 'w') as f: + f.write(text) + if __name__ == "__main__": @@ -186,6 +507,17 @@ required=True, default=False, help="Place to dump the output") + parser.add_argument('--reuse', + required=False, + default=None, + help="Reuse existing downloads") + parser.add_argument('--no_download', + action="store_false", + required=False, + default=True, + help="Don't download, use with --reuse") opts = parser.parse_args() - parse_manifest(opts.file, opts.out) + licenses = parse_manifest(opts.file, opts.out, opts.reuse, + opts.no_download) + license_html(licenses, opts.file, opts.out) + echo '' + echo '====== ec2-publishing-scripts [/tmp/ec2-publishing-scripts] ======' ====== ec2-publishing-scripts [/tmp/ec2-publishing-scripts] ====== + cd /tmp/ec2-publishing-scripts + bzr info Standalone tree (format: unnamed) Location: branch root: . Related branches: parent branch: http://bazaar.launchpad.net/~ubuntu-on-ec2/ubuntu-on-ec2/ec2-publishing-scripts/ + bzr version-info revision-id: ben.howard@ubuntu.com-20140520224241-jcgzstf9u332a3r1 date: 2014-05-20 16:42:41 -0600 build-date: 2014-06-06 19:45:31 +0000 revno: 556 branch-nick: ec2-publishing-scripts + bzr log -p -r-1 ------------------------------------------------------------ revno: 556 committer: Ben Howard branch nick: trunk timestamp: Tue 2014-05-20 16:42:41 -0600 message: Increase wait for HVM to 5/25 minutes diff: === modified file 'publicize-build' --- publicize-build 2014-05-01 13:15:40 +0000 +++ publicize-build 2014-05-20 22:42:41 +0000 @@ -335,11 +335,11 @@ error "Missing ${AMI} in ${region}" try=$((${try} - 1)) if (( ${try} > 0 )); then - error "Sleeping 60 seconds" - sleep 60 + error "Sleeping 5 minutes" + sleep 300 error "Retry #" $((5 - ${try})) else - fail "Unable to find AMI after 300 seconds." + fail "Unable to find AMI after 25 minutes." fi fi done + echo '' + echo '====== live-build [/tmp/live-build] ======' ====== live-build [/tmp/live-build] ====== + cd /tmp/live-build + bzr info Standalone tree (format: 1.9-rich-root) Location: branch root: . Related branches: parent branch: http://bazaar.launchpad.net/~ubuntu-on-ec2/live-build/cloud-images/ + bzr version-info revision-id: ben.howard@canonical.com-20140331230745-0qe08186ylyg1pkr date: 2014-03-31 17:07:45 -0600 build-date: 2014-06-06 19:45:32 +0000 revno: 1874 branch-nick: live-build + bzr log -p -r-1 ------------------------------------------------------------ revno: 1874 [merge] committer: Ben Howard branch nick: live-build timestamp: Mon 2014-03-31 17:07:45 -0600 message: Mount dev to work with Trusty PPC64EL images diff: === modified file 'scripts/build/lb_chroot_devpts' --- scripts/build/lb_chroot_devpts 2011-11-28 17:56:01 +0000 +++ scripts/build/lb_chroot_devpts 2014-03-31 22:21:42 +0000 @@ -43,6 +43,8 @@ # Creating lock file Create_lockfile .lock + ${LB_ROOT_COMMAND} mount devtmpfs -t devtmpfs chroot/dev + if [ "${LB_USE_FAKEROOT}" != "true" ] then # Creating mountpoint @@ -76,6 +78,8 @@ fi fi + ${LB_ROOT_COMMAND} umount chroot/dev || true + # Removing stage file rm -f .stage/chroot_devpts ;; ------------------------------------------------------------ Use --include-merged or -n0 to see merged revisions. + echo '' + echo '====== vmbuilder-0.11 [/tmp/vmbuilder-0.11] ======' ====== vmbuilder-0.11 [/tmp/vmbuilder-0.11] ====== + cd /tmp/vmbuilder-0.11 + bzr info Standalone tree (format: 2a) Location: branch root: . Related branches: parent branch: http://bazaar.launchpad.net/~ubuntu-on-ec2/vmbuilder/0.11a/ + bzr version-info revision-id: ben.howard@canonical.com-20120605221454-crv9cc4612f907lh date: 2012-06-05 16:14:54 -0600 build-date: 2014-06-06 19:45:32 +0000 revno: 398 branch-nick: vmbuilder-0.11 + bzr log -p -r-1 ------------------------------------------------------------ revno: 398 committer: Ben Howard branch nick: vmbuilder timestamp: Tue 2012-06-05 16:14:54 -0600 message: Fix for allow vmbuilder to run on 12.04 LTS. diff: === modified file 'VMBuilder/plugins/ubuntu/dapper.py' --- VMBuilder/plugins/ubuntu/dapper.py 2011-05-18 20:49:25 +0000 +++ VMBuilder/plugins/ubuntu/dapper.py 2012-06-05 22:14:54 +0000 @@ -157,18 +157,15 @@ self.vm.addpkg += ['openssh-server'] def mount_dev_proc(self): - run_cmd('mount', '--bind', '/dev', '%s/dev' % self.destdir) - self.vm.add_clean_cmd('umount', '%s/dev' % self.destdir, ignore_fail=True) - - run_cmd('mount', '--bind', '/dev/pts', '%s/dev/pts' % self.destdir) + run_cmd('mkdir', '-p', '%s/dev/pts' % self.destdir) + run_cmd('mount', '-t', 'devpts', 'devpts-live', '%s/dev/pts' % self.destdir) self.vm.add_clean_cmd('umount', '%s/dev/pts' % self.destdir, ignore_fail=True) - self.run_in_target('mount', '-t', 'proc', 'proc', '/proc') + run_cmd('mount', '-t', 'proc', 'proc-live', '%s/proc' % self.destdir) self.vm.add_clean_cmd('umount', '%s/proc' % self.destdir, ignore_fail=True) def unmount_dev_proc(self): run_cmd('umount', '%s/dev/pts' % self.destdir) - run_cmd('umount', '%s/dev' % self.destdir) run_cmd('sh', '-c', 'grep -q "$1" /proc/mounts || exit 0; umount "$1"', 'umount_binfmt', "%s/proc/sys/fs/binfmt_misc" % self.destdir) run_cmd('umount', '%s/proc' % self.destdir) + echo ''