3 # Copyright (c) 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.
33 import sqlite3 as sqlite
38 from xml.etree import cElementTree
41 xmlparse = cElementTree.parse
44 from mic.archive import get_archive_suffixes
45 from mic.utils.errors import CreatorError, SquashfsError
46 from mic.utils.fs_related import find_binary_path, makedirs
47 from mic.utils.grabber import myurlgrab
48 from mic.utils.proxy import get_proxy_for
49 from mic.utils import runner
50 from mic.utils import rpmmisc
51 from mic.utils.safeurl import SafeURL
54 RPM_RE = re.compile("(.*)\.(.*) (.*)-(.*)")
55 RPM_FMT = "%(name)s.%(arch)s %(version)s-%(release)s"
56 SRPM_RE = re.compile("(.*)-(\d+.*)-(\d+\.\d+).src.rpm")
59 def build_name(kscfg, release=None, prefix = None, suffix = None):
60 """Construct and return an image name string.
62 This is a utility function to help create sensible name and fslabel
63 strings. The name is constructed using the sans-prefix-and-extension
64 kickstart filename and the supplied prefix and suffix.
66 kscfg -- a path to a kickstart file
67 release -- a replacement to suffix for image release
68 prefix -- a prefix to prepend to the name; defaults to None, which causes
70 suffix -- a suffix to append to the name; defaults to None, which causes
71 a YYYYMMDDHHMM suffix to be used
73 Note, if maxlen is less then the len(suffix), you get to keep both pieces.
76 name = os.path.basename(kscfg)
81 if release is not None:
86 suffix = time.strftime("%Y%m%d%H%M")
88 if name.startswith(prefix):
89 name = name[len(prefix):]
91 prefix = "%s-" % prefix if prefix else ""
92 suffix = "-%s" % suffix if suffix else ""
94 ret = prefix + name + suffix
98 """Detect linux distribution, support "meego"
101 support_dists = ('SuSE',
109 #platform.linux_distribution was removed in Python 3.8, use distro.linux_distribution(full_distribution_name=False) instead.
110 (dist, ver, id) = distro.linux_distribution(full_distribution_name=False)
112 return (dist, ver, id)
117 return platform.node()
119 def get_hostname_distro_str():
120 """Get composited string for current linux distribution
122 (dist, ver, id) = get_distro()
123 hostname = get_hostname()
126 return "%s(Unknown Linux Distribution)" % hostname
128 distro_str = ' '.join(map(str.strip, (hostname, dist, ver, id)))
129 return distro_str.strip()
131 _LOOP_RULE_PTH = None
133 def hide_loopdev_presentation():
134 udev_rules = "80-prevent-loop-present.rules"
136 '/usr/lib/udev/rules.d/',
137 '/lib/udev/rules.d/',
141 global _LOOP_RULE_PTH
143 for rdir in udev_rules_dir:
144 if os.path.exists(rdir):
145 _LOOP_RULE_PTH = os.path.join(rdir, udev_rules)
147 if not _LOOP_RULE_PTH:
151 with open(_LOOP_RULE_PTH, 'w') as wf:
152 wf.write('KERNEL=="loop*", ENV{UDISKS_PRESENTATION_HIDE}="1"')
154 runner.quiet('udevadm trigger')
158 def unhide_loopdev_presentation():
159 #global _LOOP_RULE_PTH
161 if not _LOOP_RULE_PTH:
165 os.unlink(_LOOP_RULE_PTH)
166 runner.quiet('udevadm trigger')
170 def extract_rpm(rpmfile, targetdir):
171 rpm2cpio = find_binary_path("rpm2cpio")
172 cpio = find_binary_path("cpio")
177 msger.verbose("Extract rpm file with cpio: %s" % rpmfile)
178 p1 = subprocess.Popen([rpm2cpio, rpmfile], stdout=subprocess.PIPE)
179 p2 = subprocess.Popen([cpio, "-idv"], stdin=p1.stdout,
180 stdout=subprocess.PIPE, stderr=subprocess.PIPE)
182 (sout, serr) = p2.communicate()
183 msger.verbose(sout.decode() or serr.decode())
187 def human_size(size):
188 """Return human readable string for Bytes size
194 measure = ['B', 'K', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y']
195 expo = int(math.log(size, 1024))
196 mant = float(size/math.pow(1024, expo))
197 return "{0:.1f}{1:s}".format(mant, measure[expo])
199 def get_block_size(file_obj):
200 """ Returns block size for file object 'file_obj'. Errors are indicated by
201 the 'IOError' exception. """
203 from fcntl import ioctl
206 # Get the block size of the host file-system for the image file by calling
207 # the FIGETBSZ ioctl (number 2).
208 binary_data = ioctl(file_obj, 2, struct.pack('I', 0))
209 return struct.unpack('I', binary_data)[0]
211 def check_space_pre_cp(src, dst):
212 """Check whether disk space is enough before 'cp' like
213 operations, else exception will be raised.
216 srcsize = get_file_size(src) * 1024 * 1024
217 freesize = get_filesystem_avail(dst)
218 if srcsize > freesize:
219 raise CreatorError("space on %s(%s) is not enough for about %s files"
220 % (dst, human_size(freesize), human_size(srcsize)))
222 def calc_hashes(file_path, hash_names, start = 0, end = None):
223 """ Calculate hashes for a file. The 'file_path' argument is the file
224 to calculate hash functions for, 'start' and 'end' are the starting and
225 ending file offset to calculate the has functions for. The 'hash_names'
226 argument is a list of hash names to calculate. Returns the the list
227 of calculated hash values in the hexadecimal form in the same order
231 end = os.path.getsize(file_path)
234 to_read = end - start
238 for hash_name in hash_names:
239 hashes.append(hashlib.new(hash_name))
241 with open(file_path, "rb") as f:
244 while read < to_read:
245 if read + chunk_size > to_read:
246 chunk_size = to_read - read
247 chunk = f.read(chunk_size)
248 for hash_obj in hashes:
249 hash_obj.update(chunk)
253 for hash_obj in hashes:
254 result.append(hash_obj.hexdigest())
258 def get_md5sum(fpath):
259 return calc_hashes(fpath, ('md5', ))[0]
261 def get_sha1sum(fpath):
262 return calc_hashes(fpath, ('sha1', ))[0]
264 def get_sha256sum(fpath):
265 return calc_hashes(fpath, ('sha256', ))[0]
267 def normalize_ksfile(ksconf, release, arch):
269 Return the name of a normalized ks file in which macro variables
270 @BUILD_ID@ and @ARCH@ are replace with real values.
272 The original ks file is returned if no special macro is used, otherwise
273 a temp file is created and returned, which will be deleted when program
279 if not arch or re.match(r'i.86', arch):
282 with open(ksconf) as f:
285 if "@ARCH@" not in ksc and "@BUILD_ID@" not in ksc:
288 msger.info("Substitute macro variable @BUILD_ID@/@ARCH@ in ks: %s" % ksconf)
289 ksc = ksc.replace("@ARCH@", arch)
290 ksc = ksc.replace("@BUILD_ID@", release)
292 fd, ksconf = tempfile.mkstemp(prefix=os.path.basename(ksconf))
293 os.write(fd, ksc.encode())
296 msger.debug('normalized ks file:%s' % ksconf)
298 def remove_temp_ks():
301 except OSError as err:
302 msger.warning('Failed to remove temp ks file:%s:%s' % (ksconf, err))
305 atexit.register(remove_temp_ks)
310 def _check_mic_chroot(rootdir):
312 return rootdir.rstrip('/') + path
314 release_files = list(map(_path, [ "/etc/moblin-release",
315 "/etc/meego-release",
316 "/etc/tizen-release"]))
318 if not any(map(os.path.exists, release_files)):
319 msger.warning("Dir %s is not a MeeGo/Tizen chroot env" % rootdir)
321 if not glob.glob(rootdir + "/boot/vmlinuz-*"):
322 msger.warning("Failed to find kernel module under %s" % rootdir)
326 def selinux_check(arch, fstypes):
328 getenforce = find_binary_path('getenforce')
332 selinux_status = runner.outs([getenforce])
333 if arch and arch.startswith("arm") and selinux_status == "Enforcing":
334 raise CreatorError("Can't create arm image if selinux is enabled, "
335 "please run 'setenforce 0' to disable selinux")
337 use_btrfs = [typ for typ in fstypes if typ == 'btrfs']
338 if use_btrfs and selinux_status == "Enforcing":
339 raise CreatorError("Can't create btrfs image if selinux is enabled,"
340 " please run 'setenforce 0' to disable selinux")
342 def get_image_type(path):
343 def _get_extension_name(path):
344 match = re.search("(?<=\.)\w+$", path)
346 return match.group(0)
350 if os.path.isdir(path):
351 _check_mic_chroot(path)
363 extension = _get_extension_name(path)
364 if extension in maptab:
365 return maptab[extension]
367 fd = open(path, "rb")
368 file_header = fd.read(1024)
370 vdi_flag = "<<< Sun VirtualBox Disk Image >>>"
371 if file_header[0:len(vdi_flag)] == vdi_flag:
374 #Checking f2fs fs type.
375 blkidcmd = find_binary_path("blkid")
376 out = runner.outs([blkidcmd, '-o', 'value', '-s', 'TYPE', path])
379 output = runner.outs(['file', path])
380 isoptn = re.compile(r".*ISO 9660 CD-ROM filesystem.*(bootable).*")
381 usbimgptn = re.compile(r".*x86 boot sector.*active.*")
382 rawptn = re.compile(r".*x86 boot sector.*")
383 vmdkptn = re.compile(r".*VMware. disk image.*")
384 ext3fsimgptn = re.compile(r".*Linux.*ext3 filesystem data.*")
385 ext4fsimgptn = re.compile(r".*Linux.*ext4 filesystem data.*")
386 btrfsimgptn = re.compile(r".*BTRFS.*")
387 if isoptn.match(output):
389 elif usbimgptn.match(output):
390 return maptab["usbimg"]
391 elif rawptn.match(output):
393 elif vmdkptn.match(output):
394 return maptab["vmdk"]
395 elif ext3fsimgptn.match(output):
397 elif ext4fsimgptn.match(output):
399 elif btrfsimgptn.match(output):
402 raise CreatorError("Cannot detect the type of image: %s" % path)
405 def get_file_size(filename):
406 """ Return size in MB unit """
407 cmd = ['du', "-s", "-b", "-B", "1M", filename]
408 rc, duOutput = runner.runtool(cmd)
410 raise CreatorError("Failed to run: %s" % ' '.join(cmd))
411 size1 = int(duOutput.split()[0])
413 cmd = ['du', "-s", "-B", "1M", filename]
414 rc, duOutput = runner.runtool(cmd)
416 raise CreatorError("Failed to run: %s" % ' '.join(cmd))
418 size2 = int(duOutput.split()[0])
419 return max(size1, size2)
422 def get_filesystem_avail(fs):
423 vfstat = os.statvfs(fs)
424 return vfstat.f_bavail * vfstat.f_bsize
426 def convert_image(srcimg, srcfmt, dstimg, dstfmt):
429 raise CreatorError("Invalid destination image format: %s" % dstfmt)
430 msger.debug("converting %s image to %s" % (srcimg, dstimg))
432 path = find_binary_path("qemu-img")
433 argv = [path, "convert", "-f", "vmdk", srcimg, "-O", dstfmt, dstimg]
434 elif srcfmt == "vdi":
435 path = find_binary_path("VBoxManage")
436 argv = [path, "internalcommands", "converttoraw", srcimg, dstimg]
438 raise CreatorError("Invalid soure image format: %s" % srcfmt)
440 rc = runner.show(argv)
442 msger.debug("convert successful")
444 raise CreatorError("Unable to convert disk to %s" % dstfmt)
446 def uncompress_squashfs(squashfsimg, outdir):
447 """Uncompress file system from squshfs image"""
448 unsquashfs = find_binary_path("unsquashfs")
449 args = [ unsquashfs, "-d", outdir, squashfsimg ]
450 rc = runner.show(args)
452 raise SquashfsError("Failed to uncompress %s." % squashfsimg)
454 def mkdtemp(dir = "/var/tmp", prefix = "mic-tmp-"):
455 """ FIXME: use the dir in mic.conf instead """
458 return tempfile.mkdtemp(dir = dir, prefix = prefix)
460 def get_repostrs_from_ks(ks):
461 def _get_temp_reponame(baseurl):
462 md5obj = hashlib.md5(baseurl)
463 tmpreponame = "%s" % md5obj.hexdigest()
468 for repodata in ks.handler.repo.repoList:
473 'includepkgs', # val is list
474 'excludepkgs', # val is list
486 if hasattr(repodata, attr) and getattr(repodata, attr):
487 repo[attr] = getattr(repodata, attr)
489 if 'name' not in repo:
490 repo['name'] = _get_temp_reponame(repodata.baseurl)
491 if hasattr(repodata, 'baseurl') and getattr(repodata, 'baseurl'):
492 repo['baseurl'] = SafeURL(getattr(repodata, 'baseurl'),
493 getattr(repodata, 'user', None),
494 getattr(repodata, 'passwd', None))
496 kickstart_repos.append(repo)
498 return kickstart_repos
500 def _get_uncompressed_data_from_url(url, filename, proxies):
501 filename = myurlgrab(url.full, filename, proxies)
503 if filename.endswith(".gz"):
505 runner.quiet(['gunzip', "-f", filename])
506 elif filename.endswith(".bz2"):
508 runner.quiet(['bunzip2', "-f", filename])
510 filename = filename.replace(suffix, "")
513 def _get_metadata_from_repo(baseurl, proxies, cachedir, reponame, filename,
514 sumtype=None, checksum=None):
515 url = baseurl.join(filename)
516 filename_tmp = str("%s/%s/%s" % (cachedir, reponame, os.path.basename(filename)))
517 if os.path.splitext(filename_tmp)[1] in (".gz", ".bz2"):
518 filename = os.path.splitext(filename_tmp)[0]
520 filename = filename_tmp
521 if sumtype and checksum and os.path.exists(filename):
523 sumcmd = find_binary_path("%ssum" % sumtype)
527 file_checksum = runner.outs([sumcmd, filename]).split()[0]
529 if file_checksum and file_checksum == checksum:
532 return _get_uncompressed_data_from_url(url,filename_tmp,proxies)
534 def get_metadata_from_repos(repos, cachedir):
535 my_repo_metadata = []
538 baseurl = repo.baseurl
540 if hasattr(repo, 'proxy'):
543 proxy = get_proxy_for(baseurl)
547 proxies = {str(baseurl.split(":")[0]): str(proxy)}
549 makedirs(os.path.join(cachedir, reponame))
550 url = baseurl.join("repodata/repomd.xml")
551 filename = os.path.join(cachedir, reponame, 'repomd.xml')
552 repomd = myurlgrab(url.full, filename, proxies)
554 root = xmlparse(repomd)
556 raise CreatorError("repomd.xml syntax error.")
558 ns = root.getroot().tag
559 ns = ns[0:ns.rindex("}")+1]
565 for elm in root.iter("%sdata" % ns):
566 if elm.attrib["type"] == "patterns":
567 filepaths['patterns'] = elm.find("%slocation" % ns).attrib['href']
568 checksums['patterns'] = elm.find("%sopen-checksum" % ns).text
569 sumtypes['patterns'] = elm.find("%sopen-checksum" % ns).attrib['type']
572 for elm in root.iter("%sdata" % ns):
573 #"group" type has no "open-checksum" filed, remove it.
574 if elm.attrib["type"] == "group_gz":
575 filepaths['comps'] = elm.find("%slocation" % ns).attrib['href']
576 checksums['comps'] = elm.find("%sopen-checksum" % ns).text
577 sumtypes['comps'] = elm.find("%sopen-checksum" % ns).attrib['type']
581 for elm in root.iter("%sdata" % ns):
582 if elm.attrib["type"] in ("primary_db", "primary"):
583 primary_type = elm.attrib["type"]
584 filepaths['primary'] = elm.find("%slocation" % ns).attrib['href']
585 checksums['primary'] = elm.find("%sopen-checksum" % ns).text
586 sumtypes['primary'] = elm.find("%sopen-checksum" % ns).attrib['type']
592 for item in ("primary", "patterns", "comps"):
593 if item not in filepaths:
594 filepaths[item] = None
596 if not filepaths[item]:
598 filepaths[item] = _get_metadata_from_repo(baseurl,
608 repokey = _get_metadata_from_repo(baseurl,
612 "repodata/repomd.xml.key")
615 msger.debug("\ncan't get %s/%s" % (baseurl, "repodata/repomd.xml.key"))
617 my_repo_metadata.append({"name":reponame,
620 "primary":filepaths['primary'],
623 "patterns":filepaths['patterns'],
624 "comps":filepaths['comps'],
626 "priority":repo.priority})
628 return my_repo_metadata
630 def get_rpmver_in_repo(repometadata):
631 for repo in repometadata:
632 if repo["primary"].endswith(".xml"):
633 root = xmlparse(repo["primary"])
634 ns = root.getroot().tag
635 ns = ns[0:ns.rindex("}")+1]
638 for elm in root.iter("%spackage" % ns):
639 if elm.find("%sname" % ns).text == 'rpm':
640 for node in list(elm):
641 if node.tag == "%sversion" % ns:
642 versionlist.append(node.attrib['ver'])
645 return next(reversed(
648 key = lambda ver: list(map(int, ver.split('.'))))))
650 elif repo["primary"].endswith(".sqlite"):
651 con = sqlite.connect(repo["primary"])
652 for row in con.execute("select version from packages where "
653 "name=\"rpm\" ORDER by version DESC"):
659 def get_arch(repometadata):
661 for repo in repometadata:
662 if repo["primary"].endswith(".xml"):
663 root = xmlparse(repo["primary"])
664 ns = root.getroot().tag
665 ns = ns[0:ns.rindex("}")+1]
666 for elm in root.iter("%spackage" % ns):
667 if elm.find("%sarch" % ns).text not in ("noarch", "src"):
668 arch = elm.find("%sarch" % ns).text
669 if arch not in archlist:
670 archlist.append(arch)
671 elif repo["primary"].endswith(".sqlite"):
672 con = sqlite.connect(repo["primary"])
673 for row in con.execute("select arch from packages where arch not in (\"src\", \"noarch\")"):
674 if row[0] not in archlist:
675 archlist.append(row[0])
680 for i in range(len(archlist)):
681 if archlist[i] not in list(rpmmisc.archPolicies.keys()):
685 while j < len(uniq_arch):
686 if archlist[i] in rpmmisc.archPolicies[uniq_arch[j]].split(':'):
689 if uniq_arch[j] in rpmmisc.archPolicies[archlist[i]].split(':'):
691 uniq_arch[j] = archlist[i]
694 uniq_arch.remove(uniq_arch[j])
698 uniq_arch.append(archlist[i])
700 return uniq_arch, archlist
702 def get_package(pkg, repometadata, arch = None):
708 elif arch not in rpmmisc.archPolicies:
711 arches = rpmmisc.archPolicies[arch].split(':')
712 arches.append('noarch')
714 for repo in repometadata:
715 if repo["primary"].endswith(".xml"):
716 root = xmlparse(repo["primary"])
717 ns = root.getroot().tag
718 ns = ns[0:ns.rindex("}")+1]
719 for elm in root.iter("%spackage" % ns):
720 if elm.find("%sname" % ns).text == pkg and elm.find("%sarch" % ns).text in arches:
721 if repo["priority"] != None:
722 tmpprior = int(repo["priority"])
723 if tmpprior < priority:
725 location = elm.find("%slocation" % ns)
726 pkgpath = "%s" % location.attrib['href']
729 elif tmpprior > priority:
731 version = elm.find("%sversion" % ns)
732 tmpver = "%s-%s" % (version.attrib['ver'], version.attrib['rel'])
735 location = elm.find("%slocation" % ns)
736 pkgpath = "%s" % location.attrib['href']
739 if repo["primary"].endswith(".sqlite"):
740 con = sqlite.connect(repo["primary"])
742 sql = 'select version, release, location_href from packages ' \
743 'where name = "%s" and arch IN ("%s")' % \
744 (pkg, '","'.join(arches))
745 for row in con.execute(sql):
746 tmpver = "%s-%s" % (row[0], row[1])
749 pkgpath = "%s" % row[2]
753 sql = 'select version, release, location_href from packages ' \
754 'where name = "%s"' % pkg
755 for row in con.execute(sql):
756 tmpver = "%s-%s" % (row[0], row[1])
759 pkgpath = "%s" % row[2]
764 makedirs("%s/packages/%s" % (target_repo["cachedir"], target_repo["name"]))
765 url = target_repo["baseurl"].join(pkgpath)
766 filename = str("%s/packages/%s/%s" % (target_repo["cachedir"], target_repo["name"], os.path.basename(pkgpath)))
767 if os.path.exists(filename):
768 ret = rpmmisc.checkRpmIntegrity('rpm', filename)
772 msger.warning("package %s is damaged: %s" %
773 (os.path.basename(filename), filename))
776 pkg = myurlgrab(url.full, filename, target_repo["proxies"])
781 def get_source_name(pkg, repometadata):
783 def get_bin_name(pkg):
784 m = RPM_RE.match(pkg)
789 def get_src_name(srpm):
790 m = SRPM_RE.match(srpm)
798 pkg_name = get_bin_name(pkg)
802 for repo in repometadata:
803 if repo["primary"].endswith(".xml"):
804 root = xmlparse(repo["primary"])
805 ns = root.getroot().tag
806 ns = ns[0:ns.rindex("}")+1]
807 for elm in root.iter("%spackage" % ns):
808 if elm.find("%sname" % ns).text == pkg_name:
809 if elm.find("%sarch" % ns).text != "src":
810 version = elm.find("%sversion" % ns)
811 tmpver = "%s-%s" % (version.attrib['ver'], version.attrib['rel'])
814 fmt = elm.find("%sformat" % ns)
816 fns = list(fmt)[0].tag
817 fns = fns[0:fns.rindex("}")+1]
818 pkgpath = fmt.find("%ssourcerpm" % fns).text
822 if repo["primary"].endswith(".sqlite"):
823 con = sqlite.connect(repo["primary"])
824 for row in con.execute("select version, release, rpm_sourcerpm from packages where name = \"%s\" and arch != \"src\"" % pkg_name):
825 tmpver = "%s-%s" % (row[0], row[1])
827 pkgpath = "%s" % row[2]
832 return get_src_name(pkgpath)
836 def get_pkglist_in_patterns(group, patterns):
840 root = xmlparse(patterns)
842 raise SyntaxError("%s syntax error." % patterns)
844 for elm in list(root.getroot()):
846 ns = ns[0:ns.rindex("}")+1]
847 name = elm.find("%sname" % ns)
848 summary = elm.find("%ssummary" % ns)
849 if name.text == group or summary.text == group:
857 for requires in list(elm):
858 if requires.tag.endswith("requires"):
865 for pkg in list(requires):
866 pkgname = pkg.attrib["name"]
867 if pkgname not in pkglist:
868 pkglist.append(pkgname)
872 def get_pkglist_in_comps(group, comps):
876 root = xmlparse(comps)
878 raise SyntaxError("%s syntax error." % comps)
880 for elm in root.iter("group"):
882 name = elm.find("name")
883 if id.text == group or name.text == group:
884 packagelist = elm.find("packagelist")
891 for require in elm.iter("packagereq"):
892 if require.tag.endswith("packagereq"):
893 pkgname = require.text
894 if pkgname not in pkglist:
895 pkglist.append(pkgname)
899 def is_statically_linked(binary):
900 return ", statically linked, " in runner.outs(['file', binary])
902 def get_qemu_arm_binary(arch):
903 if arch == "aarch64":
904 node = "/proc/sys/fs/binfmt_misc/aarch64"
905 if os.path.exists("/usr/bin/qemu-arm64") and is_statically_linked("/usr/bin/qemu-arm64"):
906 arm_binary = "qemu-arm64"
907 elif os.path.exists("/usr/bin/qemu-aarch64") and is_statically_linked("/usr/bin/qemu-aarch64"):
908 arm_binary = "qemu-aarch64"
909 elif os.path.exists("/usr/bin/qemu-arm64-static"):
910 arm_binary = "qemu-arm64-static"
911 elif os.path.exists("/usr/bin/qemu-aarch64-static"):
912 arm_binary = "qemu-aarch64-static"
914 raise CreatorError("Please install a statically-linked %s" % arm_binary)
915 elif arch == "mipsel":
916 node = "/proc/sys/fs/binfmt_misc/mipsel"
917 arm_binary = "qemu-mipsel"
918 if not os.path.exists("/usr/bin/%s" % arm_binary) or not is_statically_linked("/usr/bin/%s"):
919 arm_binary = "qemu-mipsel-static"
920 if not os.path.exists("/usr/bin/%s" % arm_binary):
921 raise CreatorError("Please install a statically-linked %s" % arm_binary)
922 elif arch == "riscv64":
923 node = "/proc/sys/fs/binfmt_misc/riscv64"
924 arm_binary = "qemu-riscv64"
925 if os.path.exists("/usr/bin/qemu-riscv64") and is_statically_linked("/usr/bin/qemu-riscv64"):
926 arm_binary = "qemu-riscv64"
927 elif os.path.exists("/usr/bin/qemu-riscv64-static"):
928 arm_binary = "qemu-riscv64-static"
930 raise CreatorError("Please install a statically-linked %s" % arm_binary)
932 node = "/proc/sys/fs/binfmt_misc/arm"
933 arm_binary = "qemu-arm"
934 if not os.path.exists("/usr/bin/qemu-arm") or not is_statically_linked("/usr/bin/qemu-arm"):
935 arm_binary = "qemu-arm-static"
936 if not os.path.exists("/usr/bin/%s" % arm_binary):
937 raise CreatorError("Please install a statically-linked %s" % arm_binary)
939 return (arm_binary, node)
941 def setup_qemu_emulator(rootdir, arch):
943 # mount binfmt_misc if it doesn't exist
944 if not os.path.exists("/proc/sys/fs/binfmt_misc"):
945 modprobecmd = find_binary_path("modprobe")
946 runner.show([modprobecmd, "binfmt_misc"])
947 if not os.path.exists("/proc/sys/fs/binfmt_misc/register"):
948 mountcmd = find_binary_path("mount")
949 runner.show([mountcmd, "-t", "binfmt_misc", "none", "/proc/sys/fs/binfmt_misc"])
951 # qemu_emulator is a special case, we can't use find_binary_path
952 # qemu emulator should be a statically-linked executable file
954 arm_binary, node = get_qemu_arm_binary(arch)
955 except CreatorError as err:
957 qemu_emulator = "/usr/bin/%s" % arm_binary
959 if not os.path.exists(rootdir + "/usr/bin"):
960 makedirs(rootdir + "/usr/bin")
961 shutil.copy(qemu_emulator, rootdir + qemu_emulator)
962 qemu_emulators.append(qemu_emulator)
964 # disable selinux, selinux will block qemu emulator to run
965 if os.path.exists("/usr/sbin/setenforce"):
966 msger.info('Try to disable selinux')
967 runner.show(["/usr/sbin/setenforce", "0"])
969 # register qemu emulator for interpreting other arch executable file
970 if not os.path.exists(node):
971 if arch == "aarch64":
972 qemu_arm_string = ":aarch64:M::\\x7fELF\\x02\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\xb7:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff:%s:\n" % qemu_emulator
973 elif arch == "mipsel":
974 qemu_arm_string = ":mipsel:M::\\x7fELF\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x08\\x00:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xfe\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff\\xff:%s:\n" % qemu_emulator
975 elif arch == "riscv64":
976 qemu_arm_string = ":riscv64:M::\\x7fELF\\x02\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\xf3\\x00:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfe\\xff\\xff\\xff:%s:\n" % qemu_emulator
978 qemu_arm_string = ":arm:M::\\x7fELF\\x01\\x01\\x01\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02\\x00\\x28\\x00:\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\x00\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xff\\xfa\\xff\\xff\\xff:%s:\n" % qemu_emulator
980 with open("/proc/sys/fs/binfmt_misc/register", "w") as fd:
981 fd.write(qemu_arm_string)
985 with open(node, "r") as fd:
986 for line in fd.readlines():
987 if line.startswith("flags:"):
988 flags = line[len("flags:"):].strip()
989 elif line.startswith("interpreter"):
990 interpreter = line[len("interpreter"):].strip()
992 if flags == "P" and interpreter.endswith("-binfmt"):
993 # copy binfmt wrapper when preserve-argv[0] flag is enabled
994 shutil.copy(os.path.realpath(interpreter), rootdir + interpreter)
995 qemu_emulators.append(interpreter)
996 elif not flags and interpreter != qemu_emulator:
997 # create symlink as registered qemu emulator
998 os.symlink(qemu_emulator, rootdir + interpreter)
999 qemu_emulators.append(interpreter)
1001 return qemu_emulators
1003 def SrcpkgsDownload(pkgs, repometadata, instroot, cachedir):
1004 def get_source_repometadata(repometadata):
1006 for repo in repometadata:
1007 if repo["name"].endswith("-source"):
1008 src_repometadata.append(repo)
1009 if src_repometadata:
1010 return src_repometadata
1013 def get_src_name(srpm):
1014 m = SRPM_RE.match(srpm)
1019 src_repometadata = get_source_repometadata(repometadata)
1021 if not src_repometadata:
1022 msger.warning("No source repo found")
1028 for repo in src_repometadata:
1029 cachepath = "%s/%s/packages/*.src.rpm" %(cachedir, repo["name"])
1030 lpkgs_path += glob.glob(cachepath)
1032 for lpkg in lpkgs_path:
1033 lpkg_name = get_src_name(os.path.basename(lpkg))
1034 lpkgs_dict[lpkg_name] = lpkg
1035 localpkgs = list(lpkgs_dict.keys())
1038 destdir = instroot+'/usr/src/SRPMS'
1039 if not os.path.exists(destdir):
1040 os.makedirs(destdir)
1044 srcpkg_name = get_source_name(_pkg, repometadata)
1047 srcpkgset.add(srcpkg_name)
1049 for pkg in list(srcpkgset):
1050 if pkg in localpkgs:
1052 shutil.copy(lpkgs_dict[pkg], destdir)
1053 src_pkgs.append(os.path.basename(lpkgs_dict[pkg]))
1055 src_pkg = get_package(pkg, src_repometadata, 'src')
1057 shutil.copy(src_pkg, destdir)
1058 src_pkgs.append(src_pkg)
1059 msger.info("%d source packages gotten from cache" % cached_count)
1063 def strip_end(text, suffix):
1064 if not text.endswith(suffix):
1066 return text[:-len(suffix)]
1068 def strip_archive_suffix(filename):
1069 for suffix in get_archive_suffixes():
1070 if filename.endswith(suffix):
1071 return filename[:-len(suffix)]
1073 msger.warning("Not supported archive file format: %s" % filename)