def do_install_disk(self, disk, disk_name, cr, workdir, oe_builddir, bootimg_dir, kernel_dir, native_sysroot): """ Called after all partitions have been prepared and assembled into a disk image. In this case, we install the MBR. """ mbrfile = "%s/syslinux/" % bootimg_dir if cr._ptable_format == 'gpt': mbrfile += "gptmbr.bin" else: mbrfile += "mbr.bin" if not os.path.exists(mbrfile): msger.error( "Couldn't find %s. If using the -e option, do you have the right MACHINE set in local.conf? If not, is the bootimg_dir path correct?" % mbrfile) full_path = cr._full_path(workdir, disk_name, "direct") msger.debug("Installing MBR on disk %s as %s with size %s bytes" \ % (disk_name, full_path, disk['min_size'])) rc = runner.show( ['dd', 'if=%s' % mbrfile, 'of=%s' % full_path, 'conv=notrunc']) if rc != 0: raise MountError("Unable to set MBR to %s" % full_path)
def __copy_kernel_and_initramfs(self, isodir, version, index): bootdir = self._instroot + "/boot" isDracut = False if self._alt_initrd_name: src_initrd_path = os.path.join(bootdir, self._alt_initrd_name) else: if os.path.exists(bootdir + "/initramfs-" + version + ".img"): src_initrd_path = os.path.join(bootdir, "initramfs-" +version+ ".img") isDracut = True else: src_initrd_path = os.path.join(bootdir, "initrd-" +version+ ".img") try: msger.debug("copy %s to %s" % (bootdir + "/vmlinuz-" + version, isodir + "/isolinux/vmlinuz" + index)) shutil.copyfile(bootdir + "/vmlinuz-" + version, isodir + "/isolinux/vmlinuz" + index) msger.debug("copy %s to %s" % (src_initrd_path, isodir + "/isolinux/initrd" + index + ".img")) shutil.copyfile(src_initrd_path, isodir + "/isolinux/initrd" + index + ".img") except: raise CreatorError("Unable to copy valid kernels or initrds, " "please check the repo.") is_xen = False if os.path.exists(bootdir + "/xen.gz-" + version[:-3]): shutil.copyfile(bootdir + "/xen.gz-" + version[:-3], isodir + "/isolinux/xen" + index + ".gz") is_xen = True return (is_xen,isDracut)
def generate_bmap(self): """ Generate block map file for the image. The idea is that while disk images we generate may be large (e.g., 4GiB), they may actually contain only little real data, e.g., 512MiB. This data are files, directories, file-system meta-data, partition table, etc. In other words, when flashing the image to the target device, you do not have to copy all the 4GiB of data, you can copy only 512MiB of it, which is 4 times faster. This function generates the block map file for an arbitrary image that mic has generated. The block map file is basically an XML file which contains a list of blocks which have to be copied to the target device. The other blocks are not used and there is no need to copy them. """ if self.bmap_needed is None: return msger.info("Generating the map file(s)") for name in self.__disks.keys(): image = self._full_path(self.__imgdir, name, self.__disk_format) bmap_file = self._full_path(self._outdir, name, "bmap") self.image_files.setdefault(name, {}).update({'bmap': \ os.path.basename(bmap_file)}) msger.debug("Generating block map file '%s'" % bmap_file) bmaptoolcmd = misc.find_binary_path('bmaptool') rc = runner.show([bmaptoolcmd, 'create', image, '-o', bmap_file]) if rc != 0: raise CreatorError("Failed to create bmap file: %s" % bmap_file)
def kill_processes(chrootdir): import glob, time for fp in glob.glob("/proc/*/root"): try: if os.readlink(fp) == chrootdir: pid = int(fp.split("/")[2]) msger.debug("Terminating %s" % pid) os.kill(pid, 15) except FileNotFoundError: # Skip defunct processes pass except Exception as e: msger.warning("Failed to terminate %s %s" % (fp, e)) time.sleep(5) for fp in glob.glob("/proc/*/root"): try: if os.readlink(fp) == chrootdir: pid = int(fp.split("/")[2]) msger.debug("Killing %s" % pid) os.kill(pid, 9) except FileNotFoundError: # Skip defunct processes pass except Exception as e: msger.warning("Failed to kill %s %s" % (fp, e)) time.sleep(2)
def exec_native_cmd(cmd_and_args, native_sysroot, catch = 3): """ Execute native command, catching stderr, stdout Need to execute as_shell if the command uses wildcards Always need to execute native commands as_shell """ native_paths = \ "export PATH=%s/sbin:%s/usr/sbin:%s/usr/bin:$PATH" % \ (native_sysroot, native_sysroot, native_sysroot) native_cmd_and_args = "%s;%s" % (native_paths, cmd_and_args) msger.debug("exec_native_cmd: %s" % cmd_and_args) args = cmd_and_args.split() msger.debug(args) rc, out = exec_cmd(native_cmd_and_args, True, catch) if rc == 127: # shell command-not-found msger.error("A native (host) program required to build the image " "was not found (see details above). Please make sure " "it's installed and try again.") return (rc, out)
def _mount_instroot(self, base_on=None): self.__imgdir = self._mkdtemp() parts = self._get_parts() #create disk for item in self.get_diskinfo(): msger.debug("Adding disk %s as %s/%s-%s.raw" % (item['name'], self.__imgdir, self.name, item['name'])) disk = fs_related.SparseLoopbackDisk( "%s/%s-%s.raw" % (self.__imgdir, self.name, item['name']), item['size']) self.__disks[item['name']] = disk self.__instloop = PartitionedMount(self.__disks, self._instroot) for p in parts: self.__instloop.add_partition(int(p.size), p.disk, p.mountpoint, p.fstype, fsopts=p.fsopts, boot=p.active) self.__instloop.mount() self._create_mkinitrd_config()
def mount(self, options=None): if self.mounted: return if not os.path.isdir(self.mountdir): msger.debug("Creating mount point %s" % self.mountdir) os.makedirs(self.mountdir) self.rmdir = self.rmmountdir self.__create() msger.debug("Mounting %s at %s" % (self.disk.device, self.mountdir)) if options: args = [ self.mountcmd, "-o", options, self.disk.device, self.mountdir ] else: args = [self.mountcmd, self.disk.device, self.mountdir] if self.fstype: args.extend(["-t", self.fstype]) rc = runner.show(args) if rc != 0: raise MountError( "Failed to mount '%s' to '%s' with command '%s'. Retval: %s" % (self.disk.device, self.mountdir, " ".join(args), rc)) self.mounted = True
def do_prepare_partition(self, part, cr, cr_workdir, oe_builddir, bootimg_dir, kernel_dir, native_sysroot): """ Called to do the actual content population for a partition i.e. it 'prepares' the partition to be incorporated into the image. """ msger.debug("SourcePlugin: do_prepare_partition: part: %s" % part)
def _stage_final_image(self): """Stage the final system image in _outdir. write meta data """ self._resparse() if self.compress_image: for imgfile in os.listdir(self.__imgdir): if imgfile.endswith('.raw') or imgfile.endswith('bin'): imgpath = os.path.join(self.__imgdir, imgfile) msger.info("Compressing image %s" % imgfile) misc.compressing(imgpath, self.compress_image) if self.pack_to: dst = os.path.join(self._outdir, self.pack_to) msger.info("Pack all raw images to %s" % dst) misc.packing(dst, self.__imgdir) else: msger.debug("moving disks to stage location") for imgfile in os.listdir(self.__imgdir): src = os.path.join(self.__imgdir, imgfile) dst = os.path.join(self._outdir, imgfile) msger.debug("moving %s to %s" % (src,dst)) shutil.move(src,dst) self._write_image_xml()
def testDebug(self): excepted = "Debug: hello\n" msger.debug("hello") self.assertEqual("", sys.stdout.getvalue()) msger.set_loglevel("debug") msger.debug("hello") self.assertEqual(excepted, sys.stderr.getvalue())
def __format_filesystem(self): if self.skipformat: msger.debug("Skip filesystem format.") return msger.verbose("Formating %s filesystem on %s" % (self.fstype, self.disk.device)) rc = runner.show([ self.mkfscmd, "-F", "-L", self.fslabel, "-m", "1", "-b", str(self.blocksize), "-O", "^64bit", # syslinux does not support 64bit filesystems self.disk.device ]) # str(self.disk.size / self.blocksize)]) if rc != 0: raise MountError("Error creating %s filesystem on disk %s" % (self.fstype, self.disk.device)) out = runner.outs([self.dumpe2fs, '-h', self.disk.device]) self.uuid = self.__parse_field(out, "Filesystem UUID") msger.debug("Tuning filesystem on %s" % self.disk.device) runner.show([ self.tune2fs, "-c0", "-i0", "-Odir_index", "-ouser_xattr,acl", self.disk.device ])
def __format_filesystem(self): if self.skipformat: msger.debug("Skip filesystem format.") return msger.verbose("Formating %s filesystem on %s" % (self.fstype, self.disk.device)) cmdlist = [self.mkfscmd, "-F", "-L", self.fslabel, "-m", "1", "-b", str(self.blocksize)] if self.extopts: cmdlist.extend(self.extopts.split()) cmdlist.extend([self.disk.device]) rc, errout = runner.runtool(cmdlist, catch=2) if rc != 0: raise MountError("Error creating %s filesystem on disk %s:\n%s" % (self.fstype, self.disk.device, errout)) if not self.extopts: msger.debug("Tuning filesystem on %s" % self.disk.device) runner.show([self.tune2fs, "-c0", "-i0", "-Odir_index", "-ouser_xattr,acl", self.disk.device]) rc, out = runner.runtool([self.dumpe2fs, '-h', self.disk.device], catch=2) if rc != 0: raise MountError("Error dumpe2fs %s filesystem on disk %s:\n%s" % (self.fstype, self.disk.device, out)) # FIXME: specify uuid in mkfs parameter try: self.uuid = self.__parse_field(out, "Filesystem UUID") except: self.uuid = None
def package(self, destdir = "."): """Prepares the created image for final delivery. In its simplest form, this method merely copies the install root to the supplied destination directory; other subclasses may choose to package the image by e.g. creating a bootable ISO containing the image and bootloader configuration. destdir -- the directory into which the final image should be moved; this defaults to the current directory. """ self._stage_final_image() if not os.path.exists(destdir): fs.makedirs(destdir) if self._img_compression_method: if not self._img_name: raise CreatorError("Image name not set.") rc = None img_location = os.path.join(self._outdir,self._img_name) if self._img_compression_method == "bz2": bzip2 = fs.find_binary_path('bzip2') msger.info("Compressing %s with bzip2. Please wait..." \ % img_location) rc = runner.show([bzip2, "-f", img_location]) if rc: raise CreatorError("Failed to compress image %s with %s." \ % (img_location, self._img_compression_method)) for bootimg in glob.glob(os.path.dirname(img_location) + \ "/*-boot.bin"): msger.info("Compressing %s with bzip2. Please wait..." \ % bootimg) rc = runner.show([bzip2, "-f", bootimg]) if rc: raise CreatorError("Failed to compress image %s with " "%s." \ % (bootimg, self._img_compression_method)) if self._recording_pkgs: self._save_recording_pkgs(destdir) # For image formats with two or multiple image files, it will be # better to put them under a directory if self.image_format in ("raw", "vmdk", "vdi", "nand", "mrstnand"): destdir = os.path.join(destdir, "%s-%s" \ % (self.name, self.image_format)) msger.debug("creating destination dir: %s" % destdir) fs.makedirs(destdir) # Ensure all data is flushed to _outdir runner.quiet('sync') for f in os.listdir(self._outdir): shutil.move(os.path.join(self._outdir, f), os.path.join(destdir, f)) self.outimage.append(os.path.join(destdir, f)) self.do_genchecksum(os.path.join(destdir, f))
def normalize_ksfile(ksconf, release, arch): def _clrtempks(): try: os.unlink(ksconf) except: pass if not os.path.exists(ksconf): return if not release: release = "latest" if not arch or re.match(r'i.86', arch): arch = "ia32" with open(ksconf) as f: ksc = f.read() if "@ARCH@" in ksc or "@BUILD_ID@" in ksc: msger.info("Substitute macro variable @BUILD_ID@/@ARCH in ks: %s" % ksconf) ksc = ksc.replace("@ARCH@", arch) ksc = ksc.replace("@BUILD_ID@", release) fd, ksconf = tempfile.mkstemp(prefix=os.path.basename(ksconf), dir="/tmp/") os.write(fd, ksc) os.close(fd) msger.debug('new ks path %s' % ksconf) import atexit atexit.register(_clrtempks) return ksconf
def _mount_instroot(self, base_on = None): parts = self._get_parts() self.__instloop = PartitionedMount(self._instroot) for p in parts: self.__instloop.add_partition(int(p.size), p.disk, p.mountpoint, p.fstype, p.label, fsopts = p.fsopts, boot = p.active, align = p.align, part_type = p.part_type) self.__instloop.layout_partitions(self._ptable_format) # Create the disks self.__imgdir = self._mkdtemp() for disk_name, disk in self.__instloop.disks.items(): full_path = self._full_path(self.__imgdir, disk_name, "raw") msger.debug("Adding disk %s as %s with size %s bytes" \ % (disk_name, full_path, disk['min_size'])) disk_obj = fs_related.SparseLoopbackDisk(full_path, disk['min_size']) self.__disks[disk_name] = disk_obj self.__instloop.add_disk(disk_name, disk_obj) self.__instloop.mount() self._create_mkinitrd_config()
def generate_bmap(self): """ Generate block map file for the image. The idea is that while disk images we generate may be large (e.g., 4GiB), they may actually contain only little real data, e.g., 512MiB. This data are files, directories, file-system meta-data, partition table, etc. In other words, when flashing the image to the target device, you do not have to copy all the 4GiB of data, you can copy only 512MiB of it, which is 4 times faster. This function generates the block map file for an arbitrary image that mic has generated. The block map file is basically an XML file which contains a list of blocks which have to be copied to the target device. The other blocks are not used and there is no need to copy them. """ if self.bmap_needed is None: return from mic.utils import BmapCreate msger.info("Generating the map file(s)") for name in self.__disks.keys(): image = self._full_path(self.__imgdir, name, self.__disk_format) bmap_file = self._full_path(self._outdir, name, "bmap") msger.debug("Generating block map file '%s'" % bmap_file) try: creator = BmapCreate.BmapCreate(image, bmap_file) creator.generate() del creator except BmapCreate.Error as err: raise CreatorError("Failed to create bmap file: %s" % str(err))
def _install_syslinux(self): for name in self.__disks.keys(): loopdev = self.__disks[name].device # Set MBR mbrfile = "%s/usr/share/syslinux/" % self._instroot if self._ptable_format == 'gpt': mbrfile += "gptmbr.bin" else: mbrfile += "mbr.bin" msger.debug("Installing syslinux bootloader '%s' to %s" % \ (mbrfile, loopdev)) rc = runner.show(['dd', 'if=%s' % mbrfile, 'of=' + loopdev]) if rc != 0: raise MountError("Unable to set MBR to %s" % loopdev) # Ensure all data is flushed to disk before doing syslinux install runner.quiet('sync') fullpathsyslinux = fs_related.find_binary_path("extlinux") rc = runner.show([fullpathsyslinux, "-i", "%s/boot/extlinux" % self._instroot]) if rc != 0: raise MountError("Unable to install syslinux bootloader to %s" \ % loopdev)
def __create_subvolume_metadata(self): if len(self.subvolumes) == 0: return argv = [ self.btrfscmd, "subvolume", "list", self.mountdir ] rc, out = runner.runtool(argv) msger.debug(out) if rc != 0: raise MountError("Failed to get subvolume id from %s', return code: %d." % (self.mountdir, rc)) subvolid_items = out.splitlines() subvolume_metadata = "" for subvol in self.subvolumes: for line in subvolid_items: if line.endswith(" path %s" % subvol["subvol"]): subvolid = line.split()[1] if not subvolid.isdigit(): raise MountError("Invalid subvolume id: %s" % subvolid) subvolid = int(subvolid) fsopts = subvol["fsopts"] subvolume_metadata += "%d\t%s\t%s\t%s\n" % (subvolid, subvol["subvol"], subvol['mountpoint'], fsopts) if subvolume_metadata: fd = open("%s.subvolume_metadata" % self.disk.lofile,"w") #fd = open("%s/.subvolume_metadata" % self.mountdir, "w") fd.write(subvolume_metadata) fd.close()
def __format_filesystem(self): if self.skipformat: msger.debug("Skip filesystem format.") return msger.verbose("Formating %s filesystem on %s" % (self.fstype, self.disk.device)) cmdlist = [self.mkfscmd, "-F", "-L", self.fslabel, "-m", "1", "-b", str(self.blocksize)] if self.extopts: cmdlist.extend(self.extopts.split()) cmdlist.extend([self.disk.device]) rc, errout = runner.runtool(cmdlist, catch=2) if rc != 0: raise MountError("Error creating %s filesystem on disk %s:\n%s" % (self.fstype, self.disk.device, errout)) if not self.extopts: msger.debug("Tuning filesystem on %s" % self.disk.device) runner.show([self.tune2fs, "-c0", "-i0", "-Odir_index", "-ouser_xattr,acl", self.disk.device]) rc, errout = runner.runtool([self.dumpe2fs, '-h', self.disk.device], catch=2) if rc != 0: raise MountError("Error dumpe2fs %s filesystem on disk %s:\n%s" % (self.fstype, self.disk.device, errout)) # FIXME: specify uuid in mkfs parameter try: self.uuid = self.__parse_field(out, "Filesystem UUID") except: self.uuid = None
def __create_subvolume_metadata(self, p, pdisk): if len(self.subvolumes) == 0: return argv = [ self.btrfscmd, "subvolume", "list", pdisk.mountdir ] rc, out = runner.runtool(argv) msger.debug(out) if rc != 0: raise MountError("Failed to get subvolume id from %s', return code: %d." % (pdisk.mountdir, rc)) subvolid_items = out.splitlines() subvolume_metadata = "" for subvol in self.subvolumes: for line in subvolid_items: if line.endswith(" path %s" % subvol["subvol"]): subvolid = line.split()[1] if not subvolid.isdigit(): raise MountError("Invalid subvolume id: %s" % subvolid) subvolid = int(subvolid) opts = subvol["fsopts"].split(",") for opt in opts: if opt.strip().startswith("subvol="): opts.remove(opt) break fsopts = ",".join(opts) subvolume_metadata += "%d\t%s\t%s\t%s\n" % (subvolid, subvol["subvol"], subvol['mountpoint'], fsopts) if subvolume_metadata: fd = open("%s/.subvolume_metadata" % pdisk.mountdir, "w") fd.write(subvolume_metadata) fd.close()
def do_stage_partition(self, part, cr, workdir, oe_builddir, bootimg_dir, kernel_dir, native_sysroot): """ Special content staging hook called before do_prepare_partition(), normally empty. For galileo, we need to stage just the boot/ dir in the deploy dir. """ bootimg_dir = get_bitbake_var("DEPLOY_DIR_IMAGE") if not bootimg_dir: msger.error("Couldn't find DEPLOY_DIR_IMAGE, exiting\n") # just so the result notes display it cr.set_bootimg_dir(bootimg_dir) hdddir = "%s/hdd" % workdir hdd_boot_dir = "%s/hdd/boot" % workdir boot_dir = "%s/boot" % bootimg_dir rm_cmd = "rm -rf %s" % workdir exec_cmd(rm_cmd) msger.debug("Copying %s to %s" % (boot_dir, hdd_boot_dir)) shutil.copytree(bootimg_dir+"/boot/", hdd_boot_dir) machine = get_bitbake_var("MACHINE_ARCH") if not machine: msger.error("Couldn't find MACHINE, exiting\n") install_cmd = "install -m 0644 %s/image-micro-%s.cpio.gz %s" % \ (bootimg_dir, machine, hdddir) tmp = exec_cmd(install_cmd)
def expand(self, create=False, size=None): flags = os.O_WRONLY if create: flags |= os.O_CREAT if not os.path.exists(self.lofile): makedirs(os.path.dirname(self.lofile)) if size is None: size = self.size msger.debug("Extending sparse file %s to %d" % (self.lofile, size)) if create: fd = os.open(self.lofile, flags, 0644) else: fd = os.open(self.lofile, flags) if size <= 0: size = 1 try: os.ftruncate(fd, size) except: # may be limited by 2G in 32bit env os.ftruncate(fd, 2**31L) os.close(fd)
def __format_filesystem(self): if self.skipformat: msger.debug("Skip filesystem format.") return msger.verbose("Formating %s filesystem on %s" % (self.fstype, self.disk.device)) cmdlist = [ self.mkfscmd, "-F", "-L", self.fslabel, "-m", "1", "-b", str(self.blocksize), "-U", self.uuid ] if self.extopts: cmdlist.extend(self.extopts.split()) cmdlist.extend([self.disk.device]) rc, errout = runner.runtool(cmdlist, catch=2) if rc != 0: raise MountError("Error creating %s filesystem on disk %s:\n%s" % (self.fstype, self.disk.device, errout)) if not self.extopts: msger.debug("Tuning filesystem on %s" % self.disk.device) runner.show([ self.tune2fs, "-c0", "-i0", "-Odir_index", "-ouser_xattr,acl", self.disk.device ])
def package(self, destdir="."): """Prepares the created image for final delivery. In its simplest form, this method merely copies the install root to the supplied destination directory; other subclasses may choose to package the image by e.g. creating a bootable ISO containing the image and bootloader configuration. destdir -- the directory into which the final image should be moved; this defaults to the current directory. """ self._stage_final_image() if not os.path.exists(destdir): fs.makedirs(destdir) if self._recording_pkgs: self._save_recording_pkgs(destdir) # For image formats with two or multiple image files, it will be # better to put them under a directory if self.image_format in ("raw", "vmdk", "vdi", "nand", "mrstnand"): destdir = os.path.join(destdir, "%s-%s" % (self.name, self.image_format)) msger.debug("creating destination dir: %s" % destdir) fs.makedirs(destdir) # Ensure all data is flushed to _outdir runner.quiet("sync") misc.check_space_pre_cp(self._outdir, destdir) for f in os.listdir(self._outdir): shutil.move(os.path.join(self._outdir, f), os.path.join(destdir, f)) self.outimage.append(os.path.join(destdir, f)) self.do_genchecksum(os.path.join(destdir, f))
def exec_native_cmd(cmd_and_args, native_sysroot, catch=3): """ Execute native command, catching stderr, stdout Need to execute as_shell if the command uses wildcards Always need to execute native commands as_shell """ native_paths = \ "export PATH=%s/sbin:%s/usr/sbin:%s/usr/bin:$PATH" % \ (native_sysroot, native_sysroot, native_sysroot) native_cmd_and_args = "%s;%s" % (native_paths, cmd_and_args) msger.debug("exec_native_cmd: %s" % cmd_and_args) args = cmd_and_args.split() msger.debug(args) rc, out = exec_cmd(native_cmd_and_args, True, catch) if rc == 127: # shell command-not-found msger.error("A native (host) program required to build the image " "was not found (see details above). Please make sure " "it's installed and try again.") return (rc, out)
def _mount_instroot(self, base_on = None): self.__imgdir = self._mkdtemp() parts = self._get_parts() #create disk for item in self.get_diskinfo(): msger.debug("Adding disk %s as %s/%s-%s.raw with size %s bytes" % (item['name'], self.__imgdir, self.name, item['name'], item['size'])) disk = fs_related.SparseLoopbackDisk("%s/%s-%s.raw" % ( self.__imgdir, self.name, item['name']), item['size']) self.__disks[item['name']] = disk self.__instloop = PartitionedMount(self.__disks, self._instroot) for p in parts: self.__instloop.add_partition(int(p.size), p.disk, p.mountpoint, p.fstype, fsopts = p.fsopts, boot = p.active, align = p.align) self.__instloop.mount() self._create_mkinitrd_config()
def selectGroup(self, grp, include = ksconstants.GROUP_DEFAULT): if not self.Z: self.__initialize_zypp() found = False q=zypp.PoolQuery() q.addKind(zypp.ResKind.pattern) msger.debug("looking for %s" % grp) for item in sorted( q.queryResults(self.Z.pool()), key=cmp_to_key(lambda x,y: cmpPackage(self._castKind(x), self._castKind(y))), reverse=True): xitem = self._castKind(item) summary = "%s" % xitem.summary() name = "%s" % xitem.name() msger.debug("checking %s version %s" % (name, xitem.edition())) if name == grp or summary == grp: found = True msger.info("marking pattern %s %s to be installed" % ( name, xitem.edition() )) item.status().setToBeInstalled (zypp.ResStatus.USER) break if found: if include == ksconstants.GROUP_REQUIRED: list(map( lambda p: self.deselectPackage(p), list(grp.default_packages.keys()))) return None else: raise CreatorError("Unable to find pattern: %s" % (grp,))
def addUser(self, userconfig): args = [ "/usr/sbin/useradd" ] if userconfig.groups: args += [ "--groups", string.join(userconfig.groups, ",") ] if userconfig.name: args += [ "-m"] args += [ "-d", "/home/%s" % userconfig.name ] args.append(userconfig.name) try: dev_null = os.open("/dev/null", os.O_WRONLY) msger.debug('adding user with %s' % args) subprocess.call(args, stdout = dev_null, stderr = dev_null, preexec_fn = self.chroot) os.close(dev_null) except: msger.warning('Cannot add user using "useradd"') if userconfig.password not in (None, ""): if userconfig.isCrypted: self.set_encrypted_passwd(userconfig.name, userconfig.password) else: self.set_unencrypted_passwd(userconfig.name, userconfig.password) else: self.set_empty_passwd(userconfig.name) else: raise errors.KsError("Invalid kickstart command: %s" \ % userconfig.__str__())
def expand(self, create = False, size = None): flags = os.O_WRONLY if create: flags |= os.O_CREAT if not os.path.exists(self.lofile): makedirs(os.path.dirname(self.lofile)) if size is None: size = self.size msger.debug("Extending sparse file %s to %d" % (self.lofile, size)) if create: fd = os.open(self.lofile, flags, 0644) else: fd = os.open(self.lofile, flags) if size <= 0: size = 1 try: os.ftruncate(fd, size) except: # may be limited by 2G in 32bit env os.ftruncate(fd, 2**31L) os.close(fd)
def _install_syslinux(self): i = 0 for name in self.__disks.keys(): loopdev = self.__disks[name].device i =i+1 msger.debug("Installing syslinux bootloader to %s" % loopdev) (bootdevnum, rootdevnum, rootdev, prefix) = self._get_syslinux_boot_config() #Set MBR mbrsize = os.stat("%s/usr/share/syslinux/mbr.bin" % self._instroot)[stat.ST_SIZE] rc = runner.show(['dd', "if=%s/usr/share/syslinux/mbr.bin" % self._instroot, "of=" + loopdev]) if rc != 0: raise MountError("Unable to set MBR to %s" % loopdev) #Set Bootable flag parted = fs_related.find_binary_path("parted") rc = runner.quiet([parted, "-s", loopdev, "set", "%d" % (bootdevnum + 1), "boot", "on"]) #XXX disabled return code check because parted always fails to #reload part table with loop devices. Annoying because we can't #distinguish this failure from real partition failures :-( if rc != 0 and 1 == 0: raise MountError("Unable to set bootable flag to %sp%d" % (loopdev, (bootdevnum + 1))) #Ensure all data is flushed to disk before doing syslinux install runner.quiet('sync') fullpathsyslinux = fs_related.find_binary_path("extlinux") rc = runner.show([fullpathsyslinux, "-i", "%s/boot/extlinux" % self._instroot]) if rc != 0: raise MountError("Unable to install syslinux bootloader to %sp%d" % (loopdev, (bootdevnum + 1)))
def mount(self, options = None): if self.mounted: return if not os.path.isdir(self.mountdir): msger.debug("Creating mount point %s" % self.mountdir) os.makedirs(self.mountdir) self.rmdir = self.rmmountdir self.__create() msger.debug("Mounting %s at %s" % (self.disk.device, self.mountdir)) if options: args = [ self.mountcmd, "-o", options, self.disk.device, self.mountdir ] else: args = [ self.mountcmd, self.disk.device, self.mountdir ] if self.fstype: args.extend(["-t", self.fstype]) rc = runner.show(args) if rc != 0: raise MountError("Failed to mount '%s' to '%s' with command '%s'. Retval: %s" % (self.disk.device, self.mountdir, " ".join(args), rc)) self.mounted = True
def _install_syslinux(self): for name in self.__disks.keys(): loopdev = self.__disks[name].device # Set MBR mbrfile = "%s/usr/share/syslinux/" % self._instroot if self._ptable_format == 'gpt': mbrfile += "gptmbr.bin" else: mbrfile += "mbr.bin" msger.debug("Installing syslinux bootloader '%s' to %s" % \ (mbrfile, loopdev)) mbrsize = os.stat(mbrfile)[stat.ST_SIZE] rc = runner.show(['dd', 'if=%s' % mbrfile, 'of=' + loopdev]) if rc != 0: raise MountError("Unable to set MBR to %s" % loopdev) # Ensure all data is flushed to disk before doing syslinux install runner.quiet('sync') fullpathsyslinux = fs_related.find_binary_path("extlinux") rc = runner.show([fullpathsyslinux, "-i", "%s/boot/extlinux" % self._instroot]) if rc != 0: raise MountError("Unable to install syslinux bootloader to %s" \ % loopdev)
def addUser(self, userconfig): args = ["/usr/sbin/useradd"] if userconfig.groups: args += ["--groups", string.join(userconfig.groups, ",")] if userconfig.name: args += ["-m"] args += ["-d", "/home/%s" % userconfig.name] args.append(userconfig.name) try: dev_null = os.open("/dev/null", os.O_WRONLY) msger.debug('adding user with %s' % args) subprocess.call(args, stdout=dev_null, stderr=dev_null, preexec_fn=self.chroot) os.close(dev_null) except: msger.warning('Cannot add user using "useradd"') if userconfig.password not in (None, ""): if userconfig.isCrypted: self.set_encrypted_passwd(userconfig.name, userconfig.password) else: self.set_unencrypted_passwd(userconfig.name, userconfig.password) else: self.set_empty_passwd(userconfig.name) else: raise errors.KsError("Invalid kickstart command: %s" \ % userconfig.__str__())
def do_install_disk(self, disk, disk_name, cr, workdir, oe_builddir, bootimg_dir, kernel_dir, native_sysroot): """ Called after all partitions have been prepared and assembled into a disk image. This provides a hook to allow finalization of a disk image e.g. to write an MBR to it. """ msger.debug("SourcePlugin: do_install_disk: disk: %s" % disk_name)
def do_configure_partition(self, part, cr, cr_workdir, oe_builddir, bootimg_dir, kernel_dir, native_sysroot): """ Called before do_prepare_partition(), typically used to create custom configuration files for a partition, for example syslinux or grub config files. """ msger.debug("SourcePlugin: do_configure_partition: part: %s" % part)
def truncate(self, size=None): if size is None: size = self.size msger.debug("Truncating sparse file %s to %d" % (self.lofile, size)) fd = os.open(self.lofile, os.O_WRONLY) os.ftruncate(fd, size) os.close(fd)
def truncate(self, size = None): if size is None: size = self.size msger.debug("Truncating sparse file %s to %d" % (self.lofile, size)) fd = os.open(self.lofile, os.O_WRONLY) os.ftruncate(fd, size) os.close(fd)
def __mount_subvolumes(self, p, pdisk): if self.skipformat: # Get subvolume info self.__get_subvolume_metadata(p, pdisk) # Set default mount options if len(self.subvolumes) != 0: for subvol in self.subvolumes: if subvol["mountpoint"] == p["mountpoint"] == "/": opts = subvol["fsopts"].split(",") for opt in opts: if opt.strip().startswith("subvol="): opts.remove(opt) break pdisk.fsopts = ",".join(opts) break if len(self.subvolumes) == 0: # Return directly if no subvolumes return # Remount to make default subvolume mounted rc = runner.show([self.umountcmd, pdisk.mountdir]) if rc != 0: raise MountError("Failed to umount %s" % pdisk.mountdir) rc = runner.show([ self.mountcmd, "-o", pdisk.fsopts, pdisk.disk.device, pdisk.mountdir ]) if rc != 0: raise MountError("Failed to umount %s" % pdisk.mountdir) for subvol in self.subvolumes: if subvol["mountpoint"] == "/": continue subvolid = self.__get_subvolume_id(pdisk.mountdir, subvol["subvol"]) if subvolid == -1: msger.debug("WARNING: invalid subvolume %s" % subvol["subvol"]) continue # Replace subvolume name with subvolume ID opts = subvol["fsopts"].split(",") for opt in opts: if opt.strip().startswith("subvol="): opts.remove(opt) break opts.extend(["subvolrootid=0", "subvol=%s" % subvol["subvol"]]) fsopts = ",".join(opts) subvol['fsopts'] = fsopts mountpoint = self.mountdir + subvol['mountpoint'] makedirs(mountpoint) rc = runner.show( [self.mountcmd, "-o", fsopts, pdisk.disk.device, mountpoint]) if rc != 0: raise MountError("Failed to mount subvolume %s to %s" % (subvol["subvol"], mountpoint)) subvol["mounted"] = True
def generate_bmap(self): """ Generate block map file for an image. The idea is that while disk images we generate may be large (e.g., 4GiB), they may actually contain only little real data, e.g., 512MiB. This data are files, directories, file-system meta-data, partition table, etc. In other words, when flashing the image to the target device, you do not have to copy all the 4GiB of data, you can copy only 512MiB of it, which is 4 times faster. This function generates the block map file for an arbitrary image that mic has generated. The block map file is basically an XML file which contains a list of blocks which have to be copied to the target device. The other blocks are not used and there is no need to copy them. This function assumes the image file was originally created as a sparse file. To generate the block map we use the FIBMAP ioctl. """ if self.bmap_needed is None: return msger.info("Generating the map file(s)") for name in self.__disks.keys(): image = self._full_path(self.__imgdir, name, self.__disk_format) bmap_file = self._full_path(self.__imgdir, name, "bmap") msger.debug("Generating block map file '%s'" % bmap_file) image_size = os.path.getsize(image) with open(bmap_file, "w") as f_bmap: with open(image, "rb") as f_image: # Get the block size of the host file-system for the image # file by calling the FIGETBSZ ioctl (number 2). block_size = unpack('I', ioctl(f_image, 2, pack('I', 0)))[0] blocks_cnt = (image_size + block_size - 1) / block_size # Write general information to the block map file, without # block map itself, which will be written next. xml = self._bmap_file_start(block_size, image_size, blocks_cnt) f_bmap.write(xml) # Generate the block map and write it to the XML block map # file as we go. mapped_cnt = 0 for first, last in self._get_ranges(f_image, blocks_cnt): mapped_cnt += last - first + 1 sha1 = misc.calc_hashes(image, ('sha1', ), first * block_size, (last + 1) * block_size) f_bmap.write("\t\t<Range sha1=\"%s\"> %s-%s " \ "</Range>\n" % (sha1[0], first, last)) # Finish the block map file xml = self._bmap_file_end(mapped_cnt, block_size, blocks_cnt) f_bmap.write(xml)
def __calculate_mountorder(self): msger.debug("Calculating mount order") for p in self.partitions: self.mountOrder.append(p['mountpoint']) self.unmountOrder.append(p['mountpoint']) self.mountOrder.sort() self.unmountOrder.sort() self.unmountOrder.reverse()
def install(self, repo_urls=None): """ Install fs images into partitions """ for disk_name, disk in self.__instimage.disks.items(): full_path = self._full_path(self.__imgdir, disk_name, "direct") msger.debug("Installing disk %s as %s with size %s bytes" \ % (disk_name, full_path, disk['min_size'])) self.__instimage.install(full_path)
def _create_syslinux_config(self): #Copy splash splash = "%s/usr/lib/anaconda-runtime/syslinux-vesa-splash.jpg" % self._instroot if os.path.exists(splash): shutil.copy(splash, "%s%s/splash.jpg" % (self._instroot, "/boot/extlinux")) splashline = "menu background splash.jpg" else: splashline = "" (bootdevnum, rootdevnum, rootdev, prefix) = self._get_syslinux_boot_config() options = self.ks.handler.bootloader.appendLine #XXX don't hardcode default kernel - see livecd code syslinux_conf = "" syslinux_conf += "prompt 0\n" syslinux_conf += "timeout 1\n" syslinux_conf += "\n" syslinux_conf += "default vesamenu.c32\n" syslinux_conf += "menu autoboot Starting %s...\n" % self.distro_name syslinux_conf += "menu hidden\n" syslinux_conf += "\n" syslinux_conf += "%s\n" % splashline syslinux_conf += "menu title Welcome to %s!\n" % self.distro_name syslinux_conf += "menu color border 0 #ffffffff #00000000\n" syslinux_conf += "menu color sel 7 #ffffffff #ff000000\n" syslinux_conf += "menu color title 0 #ffffffff #00000000\n" syslinux_conf += "menu color tabmsg 0 #ffffffff #00000000\n" syslinux_conf += "menu color unsel 0 #ffffffff #00000000\n" syslinux_conf += "menu color hotsel 0 #ff000000 #ffffffff\n" syslinux_conf += "menu color hotkey 7 #ffffffff #ff000000\n" syslinux_conf += "menu color timeout_msg 0 #ffffffff #00000000\n" syslinux_conf += "menu color timeout 0 #ffffffff #00000000\n" syslinux_conf += "menu color cmdline 0 #ffffffff #00000000\n" versions = [] kernels = self._get_kernel_versions() for kernel in kernels: for version in kernels[kernel]: versions.append(version) footlabel = 0 for v in versions: shutil.copy("%s/boot/vmlinuz-%s" %(self._instroot, v), "%s%s/vmlinuz-%s" % (self._instroot, "/boot/extlinux/", v)) syslinux_conf += "label %s%d\n" % (self.distro_name.lower(), footlabel) syslinux_conf += "\tmenu label %s (%s)\n" % (self.distro_name, v) syslinux_conf += "\tkernel vmlinuz-%s\n" % v syslinux_conf += "\tappend ro root=%s quiet vga=current %s\n" % (rootdev, options) if footlabel == 0: syslinux_conf += "\tmenu default\n" footlabel += 1; msger.debug("Writing syslinux config %s/boot/extlinux/extlinux.conf" % self._instroot) cfg = open(self._instroot + "/boot/extlinux/extlinux.conf", "w") cfg.write(syslinux_conf) cfg.close()
def do_prepare_partition(self, part, cr, cr_workdir, oe_builddir, bootimg_dir, kernel_dir, rootfs_dir, native_sysroot): """ Called to do the actual content population for a partition i.e. it 'prepares' the partition to be incorporated into the image. In this case, prepare content for the special micro-galileo boot partition. """ staging_kernel_dir = kernel_dir staging_data_dir = bootimg_dir hdddir = "%s/hdd" % cr_workdir install_cmd = "install -m 0644 %s/bzImage %s/bzImage" % \ (staging_kernel_dir, hdddir) tmp = exec_cmd(install_cmd) du_cmd = "du -bks %s" % hdddir rc, out = exec_cmd(du_cmd) blocks = int(out.split()[0]) extra_blocks = part.get_extra_block_count(blocks) if extra_blocks < BOOTDD_EXTRA_SPACE: extra_blocks = BOOTDD_EXTRA_SPACE blocks += extra_blocks msger.debug("Added %d extra blocks to %s to get to %d total blocks" % \ (extra_blocks, part.mountpoint, blocks)) # Ensure total sectors is an integral number of sectors per # track or mcopy will complain. Sectors are 512 bytes, and we # generate images with 32 sectors per track. This calculation is # done in blocks, thus the mod by 16 instead of 32. blocks += (16 - (blocks % 16)) # dosfs image, created by mkdosfs bootimg = "%s/boot.img" % cr_workdir dosfs_cmd = "mkdosfs -C %s %d" % (bootimg, blocks) exec_native_cmd(dosfs_cmd, native_sysroot) mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (bootimg, hdddir) exec_native_cmd(mcopy_cmd, native_sysroot) chmod_cmd = "chmod 644 %s" % bootimg exec_cmd(chmod_cmd) du_cmd = "du -Lbms %s" % bootimg rc, out = exec_cmd(du_cmd) bootimg_size = out.split()[0] part.set_size(bootimg_size) part.set_source_file(bootimg)
def _add_plugindir(self, path): path = os.path.abspath(os.path.expanduser(path)) if not os.path.isdir(path): msger.debug("Plugin dir is not a directory or does not exist: %s"\ % path) return if path not in self.plugin_dirs: self.plugin_dirs[path] = False
def do_prepare_partition(self, part, cr, cr_workdir, oe_builddir, bootimg_dir, kernel_dir, native_sysroot): """ Called to do the actual content population for a partition i.e. it 'prepares' the partition to be incorporated into the image. In this case, prepare content for the special iot-devkit boot partition. """ staging_kernel_dir = kernel_dir staging_data_dir = bootimg_dir hdddir = "%s/hdd" % cr_workdir install_cmd = "install -m 0644 %s/bzImage %s/bzImage" % \ (staging_kernel_dir, hdddir) tmp = exec_cmd(install_cmd) du_cmd = "du -bks %s" % hdddir rc, out = exec_cmd(du_cmd) blocks = int(out.split()[0]) extra_blocks = part.get_extra_block_count(blocks) if extra_blocks < BOOTDD_EXTRA_SPACE: extra_blocks = BOOTDD_EXTRA_SPACE blocks += extra_blocks msger.debug("Added %d extra blocks to %s to get to %d total blocks" % \ (extra_blocks, part.mountpoint, blocks)) # Ensure total sectors is an integral number of sectors per # track or mcopy will complain. Sectors are 512 bytes, and we # generate images with 32 sectors per track. This calculation is # done in blocks, thus the mod by 16 instead of 32. blocks += (16 - (blocks % 16)) # dosfs image, created by mkdosfs bootimg = "%s/boot.img" % cr_workdir dosfs_cmd = "mkdosfs -C %s %d" % (bootimg, blocks) exec_native_cmd(dosfs_cmd, native_sysroot) mcopy_cmd = "mcopy -i %s -s %s/* ::/" % (bootimg, hdddir) exec_native_cmd(mcopy_cmd, native_sysroot) chmod_cmd = "chmod 644 %s" % bootimg exec_cmd(chmod_cmd) du_cmd = "du -Lbms %s" % bootimg rc, out = exec_cmd(du_cmd) bootimg_size = out.split()[0] part.set_size(bootimg_size) part.set_source_file(bootimg)
def __format_filesystem(self): if self.skipformat: msger.debug("Skip filesystem format.") return msger.verbose("Formating %s filesystem on %s" % (self.fstype, self.disk.device)) rc = runner.show([self.mkfscmd, "-L", self.fslabel, self.disk.device]) if rc != 0: raise MountError("Error creating %s filesystem on disk %s" % (self.fstype,self.disk.device)) self.uuid = self.__parse_field(runner.outs([self.blkidcmd, self.disk.device]), "UUID")
def __format_filesystem(self): if self.skipformat: msger.debug("Skip filesystem format.") return msger.verbose("Formating %s filesystem on %s" % (self.fstype, self.disk.device)) rc = runner.show([self.mkfscmd, "-n", self.fslabel, "-i", self.uuid, self.disk.device]) if rc != 0: raise MountError("Error creating %s filesystem on disk %s" % (self.fstype,self.disk.device)) msger.verbose("Tuning filesystem on %s" % self.disk.device)