コード例 #1
0
ファイル: grub.py プロジェクト: funtoo/ego
	def generateOtherBootEntry(self, boot_menu: BootLoaderMenu, sect) -> bool:
		""" Generates the boot entry for other systems """
		mytype = self.boot_config["{s}/type".format(s=sect)].lower()
		if mytype in ["dos", "msdos"]:
			mytype = "dos"
		elif mytype in ["windows", "windows 2000", "win2000", "windows xp", "winxp"]:
			mytype = "winxp"
		elif mytype in ["windows vista", "vista"]:
			mytype = "vista"
		elif mytype in ["windows 7", "win7"]:
			mytype = "win7"
		elif mytype in ["windows 8", "win8"]:
			mytype = "win8"
		elif mytype in ["windows 10", "win10"]:
			mytype = "win10"
		elif mytype in ["haiku", "haiku os"]:
			mytype = "haiku"
		elif mytype in ["linux16"]:
			mytype = "linux16"
		else:
			self.msgs.append(["fatal", "Unrecognized boot entry type \"{mt}\"".format(mt=mytype)])
			return False
		params = self.boot_config["{s}/params".format(s=sect)].split()
		myroot = self.resolver.GetParam(params, "root=")
		mychainloader = self.resolver.GetParam(params, "chainloader=")
		myname = sect
		# TODO check for valid root entry
		boot_menu.lines.append("")
		boot_menu.lines.append("menuentry \"{mn}\" {{".format(mn=myname))
		if mytype in ["linux16"]:
			k = self.resolver.strip_mount_point(self.boot_config[sect + "/kernel"])
			full_k = os.path.join(self.boot_config["boot/path"], k.lstrip("/"))
			if not os.path.exists(full_k):
				self.msgs.append(["warn", "Image for section {sect} not found - {full_k}".format(sect=sect, full_k=full_k)])
			else:
				self.bootitems.append(myname)
				boot_menu.lines.append("  linux16 " + k)
		else:
			# TODO: add entry to boot_menu object
			self.PrepareGRUBForDevice(myroot, boot_menu.lines)
			self.bootitems.append(myname)
			self.DeviceGRUB(myroot)
			if mytype in ["win7", "win8"] or mytype == "win10" and self.uefiboot is False:
				boot_menu.lines.append("  chainloader " + mychainloader) if mychainloader else boot_menu.lines.append("  chainloader +4")
			elif mytype in ["vista", "dos", "winxp", "haiku"]:
				boot_menu.lines.append("  chainloader " + mychainloader) if mychainloader else boot_menu.lines.append("  chainloader +1")
			elif mytype in ["win10"]:
				boot_menu.lines.append("  chainloader " + mychainloader) if mychainloader else boot_menu.lines.append("  chainloader /EFI/Microsoft/Boot/bootmgfw.efi")
		boot_menu.lines.append("}")
		boot_menu.addBootEntry(BootLoaderEntryType.OTHER, label=myname)
		return True
コード例 #2
0
ファイル: resolver.py プロジェクト: funtoo/ego
	def _GenerateOtherSection(self, boot_menu: BootLoaderMenu,
							  sect: str,
							  ofunc: Callable[[BootLoaderMenu, str], bool]) -> bool:
		"""Generate section for non-Linux systems"""
		
		ok = ofunc(boot_menu, sect)
		self._defnames.append(sect)
		if self._default == sect:
			if boot_menu.default_position is not None:
				self.msgs.append(["warn", "multiple matches found for default boot entry \"{name}\" - first match used.".format(name=self._default)])
			else:
				boot_menu.default_position = self._pos
		self._pos += 1
		return ok
コード例 #3
0
    def _GenerateOtherSection(
            self, boot_menu: BootLoaderMenu, sect: str,
            ofunc: Callable[[BootLoaderMenu, str], bool]) -> bool:
        """Generate section for non-Linux systems"""

        ok = ofunc(boot_menu, sect)
        self._defnames.append(sect)
        if self._default == sect:
            if boot_menu.default_position is not None:
                self.msgs.append([
                    "warn",
                    "multiple matches found for default boot entry \"{name}\" - first match used."
                    .format(name=self._default)
                ])
            else:
                boot_menu.default_position = self._pos
        self._pos += 1
        return ok
コード例 #4
0
    def GenerateSections(
            self,
            boot_menu: BootLoaderMenu,
            sfunc: Callable[[BootLoaderMenu, str, str], bool],
            ofunc: Callable[[BootLoaderMenu, str],
                            bool] = None) -> BootLoaderMenu:
        """Generates sections using passed in extension-supplied functions"""
        try:
            timeout = int(self.boot_config["boot/timeout"])
        except ValueError:
            ok = False
            self.msgs.append(["fatal", "Invalid value for boot/timeout."])
            return boot_menu

        if timeout == 0:
            self.msgs.append([
                "warn",
                "boot/timeout value is zero - boot menu will not appear!"
            ])
        elif timeout < 3:
            self.msgs.append(
                ["norm", "boot/timeout value is below 3 seconds."])

        # Remove builtins from list of sections
        sections = self.boot_config.getSections()
        for sect in sections[:]:
            if sect in self.boot_config.builtins:
                sections.remove(sect)

        # If we have no boot entries, throw an error - force user to be
        # explicit.
        if len(sections) == 0:
            self.msgs.append(
                ["fatal", "No boot entries are defined in /etc/boot.conf."])
            boot_menu.success = False
            return boot_menu

        # Warn if there are no linux entries
        has_linux = False
        for sect in sections:
            if self.boot_config["{s}/{t}".format(s=sect, t="type")] == "linux":
                has_linux = True
                break
        if has_linux is False:
            self.msgs.append([
                "warn",
                "No Linux boot entries are defined. You may not be able to re-enter Linux."
            ])

        # Generate sections
        for sect in sections:
            if self.boot_config["{s}/type".format(s=sect)] in ["linux", "xen"]:
                ok = self._GenerateLinuxSection(boot_menu, sect, sfunc)
            elif ofunc:
                ok = self._GenerateOtherSection(boot_menu, sect, ofunc)

        if self._pos == 0:
            # this means we processed no kernels -- so we have nothing to boot!
            self.msgs.append([
                "fatal",
                "No matching kernels or boot entries found in /etc/boot.conf."
            ])
            boot_menu.success = False
            return boot_menu
        elif boot_menu.default_position is None:
            # this means we didn't pick a default kernel to boot!
            self.msgs.append([
                "warn",
                "Had difficulty finding a default kernel -- using first one."
            ])
            # If we didn't find a specified default, use the first one
            boot_menu.default_position = 0
        else:
            self.msgs.append([
                "note",
                "Default kernel selected via: %s." % self._default_mode
            ])
            # Tag the boot menu as being default for display:
            boot_menu.boot_entries[boot_menu.default_position]["flags"].append(
                BootMenuFlag.DEFAULT)
        if self._default_mode == "autopick: mtime" and self.boot_config.item(
                "boot", "autopick") == "last-booted":
            self.msgs.append([
                "warn",
                "Falling back to last modification time booting due to lack of last-booted info."
            ])

        return boot_menu
コード例 #5
0
    def _GenerateLinuxSection(
            self, boot_menu: BootLoaderMenu, sect: str,
            sfunc: Callable[[BootLoaderMenu, str, str, str], bool]) -> bool:
        """Generates section for Linux systems"""
        ok = True
        # Process a section, such as "genkernel" section.

        findlist, skiplist = self.boot_config.flagItemList(
            "{s}/kernel".format(s=sect))

        # findlist == special patterns to match (i.e. kernel[-v])
        # skiplist == patterns to skip.

        findmatch = []
        skipmatch = []

        scanpaths = self.boot_config.item(sect, "scan").split()
        for scanpath in scanpaths:
            scanpath = os.path.join(self.config.root_path,
                                    scanpath.lstrip("/"))
            if self.config.root_path == "/":
                self.mount_if_necessary(scanpath)
            if len(skiplist):
                # find kernels to skip...
                matches = self.GetMatchingKernels(scanpath, skiplist)
                skipmatch += matches
            if len(findlist):
                # find kernels to match (skipping any kernels we should skip...)
                matches = self.GetMatchingKernels(scanpath, findlist,
                                                  skipmatch)
                findmatch += matches

        # Generate individual boot entry using extension-supplied function

        found_multi = False

        # logic for finding a kernel to boot, based on default setting:
        # sort by modification time:
        findmatch = sorted(findmatch, key=lambda x: x[2], reverse=True)

        if self._default_mode == "autopick: mtime":
            # pick newest kernel by mtime, which happens to be top-of-list
            boot_menu.default_position = 0
            for kname, kext, mtime in findmatch:
                self._defnames.append(kname)
                ok = sfunc(boot_menu, sect, kname, kext)
                self._pos += 1

        else:
            def_mtime = None
            for kname, kext, mtime in findmatch:
                if (self._default == sect) or (self._default == kname) or (
                        self._default == os.path.basename(kname)):
                    # default match
                    if boot_menu.default_position is not None:
                        found_multi = True
                        if mtime > def_mtime:
                            # this kernel is newer, use it instead
                            boot_menu.default_position = self._pos
                            def_mtime = mtime
                    else:
                        boot_menu.default_position = self._pos
                        def_mtime = os.stat(kname)[8]
                self._defnames.append(kname)
                ok = sfunc(boot_menu, sect, kname, kext)
                if not ok:
                    break
                self._pos += 1

            if found_multi:
                self.msgs.append([
                    "warn",
                    "multiple matches found for default \"{name}\" - most recent used."
                    .format(name=self._default)
                ])

        return ok
コード例 #6
0
ファイル: extension.py プロジェクト: palica/ego
	def generateConfigFile(self, boot_menu: BootLoaderMenu):
		""" Generate new config file based on config data. Returns a list of all lines of the config file, without trailing newlines. """
		return BootLoaderMenu()
コード例 #7
0
ファイル: grub.py プロジェクト: funtoo/ego
	def generateConfigFile(self, boot_menu: BootLoaderMenu):
		if self.uefiboot:
			self.msgs.append(["note", "Detected UEFI boot. Configuring for UEFI booting."])
		else:
			self.msgs.append(["note", "Detected MBR boot. Configuring for Legacy MBR booting."])
		boot_menu.lines.append(self.boot_config.condFormatSubItem("boot/timeout", "set timeout={s}"))
		# pass our boot entry generator function to GenerateSections,
		# and everything is taken care of for our boot entries
		
		boot_menu.lines += [
			"",
			"if [ -s $prefix/grubenv ]; then",
			"    load_env",
			"fi",
			"",
			"function savedefault {",
			"    if [ -z \"{boot_once}\" ]; then",
			"        saved_entry=\"${chosen}\"",
			"        save_env saved_entry",
			"    fi",
			"}"
		]
		
		if self.boot_config.hasItem("boot/terminal") and self.boot_config["boot/terminal"] == "serial":
			self.msgs.append(["warn", "Configured for SERIAL input/output."])
			boot_menu.lines += [
				"serial --unit=%s --speed=%s --word=%s --parity=%s --stop=%s" % (
					self.boot_config["serial/unit"],
					self.boot_config["serial/speed"],
					self.boot_config["serial/word"],
					self.boot_config["serial/parity"],
					self.boot_config["serial/stop"]),
				"terminal_input serial",
				"terminal_output serial"
			]
		elif self.boot_config.hasItem("display/gfxmode"):
			boot_menu.lines.append("")
			self.PrepareGRUBForFilesystem(os.path.join(self.config.root_path, self.boot_config["boot/path"].lstrip('/')), boot_menu.lines)
			if self.boot_config.hasItem("display/font"):
				font = self.boot_config["display/font"]
			else:
				font = None
			
			dst_font = None
			
			if font is None:
				fonts = ["unicode.pf2", "unifont.pf2"]
			else:
				fonts = [font]
			
			for fontpath in [self.grubpath, self.grubpath + "/fonts"]:
				if dst_font is not None:
					break
				for font in fonts:
					path_to_font = fontpath + "/" + font
					full_path_to_font = os.path.join(self.config.root_path, path_to_font.lstrip("/"))
					if os.path.exists(full_path_to_font):
						dst_font = path_to_font
						break
			
			if dst_font is None:
				# font does not exist at destination... so we will need to find it somewhere and copy into /boot/grub
				for fontpath in self.boot_config["grub/font_src"].split():
					if dst_font is not None:
						break
					for font in fonts:
						path_to_font = fontpath + "/" + font
						if os.path.exists(path_to_font):
							src_font = path_to_font
							dst_font = self.grubpath + '/fonts/' + font
							dst_font = os.path.join(self.config.root_path, dst_font.lstrip("/"))
							if not os.path.exists(dst_font):
								import shutil
								shutil.copy(src_font, dst_font)
							break
			
			if dst_font is None:
				if font:
					self.msgs.append(["fatal", "specified font \"{ft}\" not found at {dst}; aborting.".format(ft=font, dst=dst_font)])
				else:
					self.msgs.append(["fatal", "Could not find one of %s to copy into boot directory; aborting." % ",".join(fonts)])
				boot_menu.success = False

			
			boot_menu.lines += ["if loadfont {dst}; then".format(dst=self.resolver.RelativePathTo(dst_font, self.boot_config["boot/path"])),
				  "   set gfxmode={gfx}".format(gfx=self.sanitizeDisplayMode(self.boot_config["display/gfxmode"])),
				  "   insmod all_video",
				  "   terminal_output gfxterm"]
			bg = self.boot_config.item("display", "background").split()
			if len(bg):
				bgimg = None
				bgext = None
				if len(bg) == 1:
					# get extension from file:
					bgimg = bg[0]
					bgext = bg[0].rsplit(".")[-1].lower()
				elif len(bg) == 2:
					# extension specified as second argument:
					bgimg, bgext = bg
				else:
					self.msgs.append(["warn", "Unexpected number of arguments for background image - skipping."])
				if bgimg is not None:
					if bgext == "jpg":
						bgext = "jpeg"
					if bgext in ["jpeg", "png", "tga"]:
						rel_cfgpath = "{path}/{img}".format(path=self.boot_config["boot/path"], img=bgimg)
						
						# first, look for absolute path, because our relative path
						# can eval to "/boot/boot/foo.png" which
						# due to the /boot/boot symlink will "exist".
						
						if bgimg[0] == "/" and os.path.exists(bgimg):
							# user specified absolute path to file on disk:
							boot_menu.lines += [
								"   insmod {bg}".format(bg=bgext),
								"   background_image {img}".format(img=self.resolver.RelativePathTo(bgimg, self.boot_config["boot/path"]))
							]
						elif os.path.exists(rel_cfgpath):
							# user specified path relative to /boot:
							boot_menu.lines += [
								"   insmod {ext}".format(ext=bgext),
								"   background_image {img}".format(img=self.resolver.RelativePathTo(rel_cfgpath, self.boot_config["boot/path"]))
							]
						else:
							self.msgs.append(["warn", "background image \"{img}\" does not exist - skipping.".format(img=bgimg)])
					else:
						self.msgs.append(["warn", "background image \"{img}\" (format \"{ext}\") not recognized - skipping.".format(img=bgimg, ext=bgext)])
			boot_menu.lines += ["fi",
								"",
								self.boot_config.condFormatSubItem("color/normal", "set menu_color_normal={s}"),
								self.boot_config.condFormatSubItem("color/highlight", "set menu_color_highlight={s}"),
								]
		else:
			if self.boot_config.hasItem("display/background"):
				self.msgs.append(["warn", "display/gfxmode not provided - display/background \"{bg}\" will not be displayed.".format(bg=self.boot_config["display/background"])])
		self.resolver.GenerateSections(boot_menu, self.generateBootEntry, self.generateOtherBootEntry)
		
		if boot_menu.user_specified_attempt_identifier:
			if boot_menu.attempt_kname is not None and boot_menu.attempt_position is not None:
				boot_menu.lines += [

				]
				# This condition indicates that we successfully found the boot entry in the boot menu:
				# Record entry on-disk as a kernel to promote to default if we succeed booting...
				self.boot_config.idmapper.update_promote_kname(boot_menu._attempt_kname)
				self._attempt_kernel(boot_menu)
			else:
				self.msgs.append(["error", "Unable to find a matching boot entry for attempted kernel you specified."])
		else:
			# make sure the *default* kernel is attempted, to wipe out any existing attempt settings.
			self._attempt_kernel(boot_menu, set_default=True)
		
		# The following lines load the GRUB env data. Then we see if "$next_entry" is set, which specifies a to-be-attempted kernel.
		# If so, it becomes the default (for one boot.) Otherwise, we look and see if "$saved_entry" is set, which is the grub env
		# variable set by "grub-set-default". If this specifies a default kernel, we'll use it. Otherwise, fall back to a hard-
		# coded value from boot-update config itself, pointing to the default kernel.
		
		boot_menu.lines += [
			"",
			"if [ ! \"${next_entry}\" = \"\" ] ; then",
			"    set default=\"${next_entry}\"",
			"    set next_entry=",
			"    save_env next_entry",
			"    set boot_once=true",
			"elif [ ! \"${saved_entry}\" = \"\" ]; then",
			"    set default=\"${saved_entry}\"",
			"else",
			"    set default={pos}".format(pos=boot_menu.default_position),
			"fi"
		]
コード例 #8
0
ファイル: grub.py プロジェクト: funtoo/ego
	def generateBootEntry(self, boot_menu: BootLoaderMenu, sect: str, k_full_path: str, kext: str) -> bool:
		""" Generates the boot entry """
		mytype = self.boot_config["{s}/type".format(s=sect)]
		boot_menu.lines.append("")
		label = self.resolver.GetBootEntryString(sect, k_full_path)
		boot_menu.lines.append("menuentry \"{l}\" {{".format(l=label))
		
		# TODO: add last-selected, which is different than last-booted.
		#if self.config["boot/autopick"] == "last-booted":
		#	boot_menu.lines.append("    savedefault")
		
		# self.bootitems records all our boot items
		self.bootitems.append(label)
		
		scanpath = os.path.join(self.config.root_path, self.boot_config.item(sect, "scan").lstrip("/"))
		
		self.PrepareGRUBForFilesystem(scanpath, boot_menu.lines)
		
		# removes ROOT env var and /boot from the kernel path:
		k_sub_path = self.resolver.strip_mount_point(k_full_path)
		c = self.boot_config
		params = []
		if c.hasItem("boot/terminal") and c["boot/terminal"] == "serial":
			params += [
				"console=tty0",
				"console=ttyS%s,%s%s%s" % (c["serial/unit"], c["serial/speed"], c["serial/parity"][0], c["serial/word"])
			]
		for param in self.boot_config["{s}/params".format(s=sect)].split():
			if param not in params:
				params.append(param)
		
		# Logic here to see if we are processing a boot entry that is a kernel we should "attempt" to boot. It gets special parameters added to its boot
		# entry. It may be tagged by the user on this call to ego boot (user_specified_attempt_identifier) or we may simply have boot_menu.attempt_kname
		# set due to an attempted kernel having been selected previously:

		entry = boot_menu.addBootEntry(BootLoaderEntryType.LINUX, label=label, image_path=k_full_path)
		if BootMenuFlag.ATTEMPT in entry["flags"]:
			# Add special boot parameters for a kernel we are attempting to boot (usually panic=10 or similar to force a reboot)
			for param in self.boot_config["{s}/attemptparams".format(s=sect)].split():
				if param not in params:
					params.append(param)
		
		# TODO: turn off panic setting after successful boot? (ego boot success?)
		
		ok, myroot = self.resolver.calculate_rootfs_for_section(params)
		if not ok:
			return False
		ok, fstype = self.resolver.calculate_filesystem_for_section(params)
		if not ok:
			return False
		
		initrds = self.boot_config.item(sect, "initrd")
		initrds = self.resolver.find_initrds(initrds, scanpath, k_full_path, kext)
		if myroot and ('root=' + myroot) in params and 0 == len(initrds):
			params.remove('root=' + myroot)
			params.append('root=' + self.resolver.resolvedev(myroot))
		
		xenpath = None
		xenparams = None
		
		# Populate xen variables if type is xen
		if mytype == "xen":
			xenkernel = self.boot_config["{s}/xenkernel".format(s=sect)]
			# Add leading / if needed
			if not xenkernel.startswith("/"):
				xenkernel = "/{xker}".format(xker=xenkernel)
			xenpath = self.resolver.strip_mount_point(xenkernel)
			xenparams = self.boot_config["{s}/xenparams".format(s=sect)].split()
		
		# Add unique identifier that can be used to determine if kernel booted.
		params.append("rand_id=%s" % self.resolver.idmapper.get(k_full_path))
		# Append kernel lines based on type
		if mytype == "xen":
			boot_menu.lines.append("  multiboot {xker} {xparams}".format(xker=xenpath, xparams=" ".join(xenparams)))
			boot_menu.lines.append("  module {ker} {params}".format(ker=k_sub_path, params=" ".join(params)))
			for initrd in initrds:
				boot_menu.lines.append("  module {initrd}".format(initrd=self.resolver.strip_mount_point(initrd)))
		else:
			boot_menu.lines.append("  {t} {k} {par}".format(t=mytype, k=k_sub_path, par=" ".join(params)))
			if initrds:
				initrds = (self.resolver.strip_mount_point(initrd) for initrd in initrds)
				boot_menu.lines.append("  initrd {rds}".format(rds=" ".join(initrds)))
		
		# Append graphics line
		if self.boot_config.hasItem("{s}/gfxmode".format(s=sect)):
			skipgfx = False
			for p in params:
				if p.startswith("vga=") or p.startswith("video=uvesafb:"):
					skipgfx = True
					break
			if not skipgfx:
				boot_menu.lines.append("  set gfxpayload=keep")
		boot_menu.lines.append("}")

		return ok
コード例 #9
0
ファイル: grub.py プロジェクト: palica/ego
    def generateConfigFile(self, boot_menu: BootLoaderMenu):
        if self.uefiboot:
            self.msgs.append(
                ["note", "Detected UEFI boot. Configuring for UEFI booting."])
        else:
            self.msgs.append([
                "note",
                "Detected MBR boot. Configuring for Legacy MBR booting."
            ])
        boot_menu.lines.append(
            self.boot_config.condFormatSubItem("boot/timeout",
                                               "set timeout={s}"))
        # pass our boot entry generator function to GenerateSections,
        # and everything is taken care of for our boot entries

        boot_menu.lines += [
            "", "if [ -s $prefix/grubenv ]; then", "    load_env", "fi", "",
            "function savedefault {", "    if [ -z \"{boot_once}\" ]; then",
            "        saved_entry=\"${chosen}\"",
            "        save_env saved_entry", "    fi", "}"
        ]

        if self.boot_config.hasItem("boot/terminal") and self.boot_config[
                "boot/terminal"] == "serial":
            self.msgs.append(["warn", "Configured for SERIAL input/output."])
            boot_menu.lines += [
                "serial --unit=%s --speed=%s --word=%s --parity=%s --stop=%s" %
                (self.boot_config["serial/unit"],
                 self.boot_config["serial/speed"],
                 self.boot_config["serial/word"],
                 self.boot_config["serial/parity"],
                 self.boot_config["serial/stop"]), "terminal_input serial",
                "terminal_output serial"
            ]
        elif self.boot_config.hasItem("display/gfxmode"):
            boot_menu.lines.append("")
            self.PrepareGRUBForFilesystem(
                os.path.join(self.config.root_path,
                             self.boot_config["boot/path"].lstrip('/')),
                boot_menu.lines)
            if self.boot_config.hasItem("display/font"):
                font = self.boot_config["display/font"]
            else:
                font = None

            dst_font = None

            if font is None:
                fonts = ["unicode.pf2", "unifont.pf2"]
            else:
                fonts = [font]

            for fontpath in [self.grubpath, self.grubpath + "/fonts"]:
                if dst_font is not None:
                    break
                for font in fonts:
                    path_to_font = fontpath + "/" + font
                    full_path_to_font = os.path.join(self.config.root_path,
                                                     path_to_font.lstrip("/"))
                    if os.path.exists(full_path_to_font):
                        dst_font = path_to_font
                        break

            if dst_font is None:
                # font does not exist at destination... so we will need to find it somewhere and copy into /boot/grub
                for fontpath in self.boot_config["grub/font_src"].split():
                    if dst_font is not None:
                        break
                    for font in fonts:
                        path_to_font = fontpath + "/" + font
                        if os.path.exists(path_to_font):
                            src_font = path_to_font
                            dst_font = self.grubpath + '/fonts/' + font
                            dst_font = os.path.join(self.config.root_path,
                                                    dst_font.lstrip("/"))
                            if not os.path.exists(dst_font):
                                import shutil
                                shutil.copy(src_font, dst_font)
                            break

            if dst_font is None:
                if font:
                    self.msgs.append([
                        "fatal",
                        "specified font \"{ft}\" not found at {dst}; aborting."
                        .format(ft=font, dst=dst_font)
                    ])
                else:
                    self.msgs.append([
                        "fatal",
                        "Could not find one of %s to copy into boot directory; aborting."
                        % ",".join(fonts)
                    ])
                boot_menu.success = False

            boot_menu.lines += [
                "if loadfont {dst}; then".format(
                    dst=self.resolver.RelativePathTo(
                        dst_font, self.boot_config["boot/path"])),
                "   set gfxmode={gfx}".format(gfx=self.sanitizeDisplayMode(
                    self.boot_config["display/gfxmode"])),
                "   insmod all_video", "   terminal_output gfxterm"
            ]
            bg = self.boot_config.item("display", "background").split()
            if len(bg):
                bgimg = None
                bgext = None
                if len(bg) == 1:
                    # get extension from file:
                    bgimg = bg[0]
                    bgext = bg[0].rsplit(".")[-1].lower()
                elif len(bg) == 2:
                    # extension specified as second argument:
                    bgimg, bgext = bg
                else:
                    self.msgs.append([
                        "warn",
                        "Unexpected number of arguments for background image - skipping."
                    ])
                if bgimg is not None:
                    if bgext == "jpg":
                        bgext = "jpeg"
                    if bgext in ["jpeg", "png", "tga"]:
                        rel_cfgpath = "{path}/{img}".format(
                            path=self.boot_config["boot/path"], img=bgimg)

                        # first, look for absolute path, because our relative path
                        # can eval to "/boot/boot/foo.png" which
                        # due to the /boot/boot symlink will "exist".

                        if bgimg[0] == "/" and os.path.exists(bgimg):
                            # user specified absolute path to file on disk:
                            boot_menu.lines += [
                                "   insmod {bg}".format(bg=bgext),
                                "   background_image {img}".format(
                                    img=self.resolver.RelativePathTo(
                                        bgimg, self.boot_config["boot/path"]))
                            ]
                        elif os.path.exists(rel_cfgpath):
                            # user specified path relative to /boot:
                            boot_menu.lines += [
                                "   insmod {ext}".format(ext=bgext),
                                "   background_image {img}".format(
                                    img=self.resolver.RelativePathTo(
                                        rel_cfgpath,
                                        self.boot_config["boot/path"]))
                            ]
                        else:
                            self.msgs.append([
                                "warn",
                                "background image \"{img}\" does not exist - skipping."
                                .format(img=bgimg)
                            ])
                    else:
                        self.msgs.append([
                            "warn",
                            "background image \"{img}\" (format \"{ext}\") not recognized - skipping."
                            .format(img=bgimg, ext=bgext)
                        ])
            boot_menu.lines += [
                "fi",
                "",
                self.boot_config.condFormatSubItem(
                    "color/normal", "set menu_color_normal={s}"),
                self.boot_config.condFormatSubItem(
                    "color/highlight", "set menu_color_highlight={s}"),
            ]
        else:
            if self.boot_config.hasItem("display/background"):
                self.msgs.append([
                    "warn",
                    "display/gfxmode not provided - display/background \"{bg}\" will not be displayed."
                    .format(bg=self.boot_config["display/background"])
                ])
        self.resolver.GenerateSections(boot_menu, self.generateBootEntry,
                                       self.generateOtherBootEntry)

        if boot_menu.user_specified_attempt_identifier:
            if boot_menu.attempt_kname is not None and boot_menu.attempt_position is not None:
                boot_menu.lines += []
                # This condition indicates that we successfully found the boot entry in the boot menu:
                # Record entry on-disk as a kernel to promote to default if we succeed booting...
                self.boot_config.idmapper.update_promote_kname(
                    boot_menu._attempt_kname)
                self._attempt_kernel(boot_menu)
            else:
                self.msgs.append([
                    "error",
                    "Unable to find a matching boot entry for attempted kernel you specified."
                ])
        else:
            # make sure the *default* kernel is attempted, to wipe out any existing attempt settings.
            self._attempt_kernel(boot_menu, set_default=True)

        # The following lines load the GRUB env data. Then we see if "$next_entry" is set, which specifies a to-be-attempted kernel.
        # If so, it becomes the default (for one boot.) Otherwise, we look and see if "$saved_entry" is set, which is the grub env
        # variable set by "grub-set-default". If this specifies a default kernel, we'll use it. Otherwise, fall back to a hard-
        # coded value from boot-update config itself, pointing to the default kernel.

        boot_menu.lines += [
            "", "if [ ! \"${next_entry}\" = \"\" ] ; then",
            "    set default=\"${next_entry}\"", "    set next_entry=",
            "    save_env next_entry", "    set boot_once=true",
            "elif [ ! \"${saved_entry}\" = \"\" ]; then",
            "    set default=\"${saved_entry}\"", "else",
            "    set default={pos}".format(pos=boot_menu.default_position),
            "fi"
        ]
コード例 #10
0
ファイル: grub.py プロジェクト: palica/ego
    def generateBootEntry(self, boot_menu: BootLoaderMenu, sect: str,
                          k_full_path: str, kext: str) -> bool:
        """ Generates the boot entry """
        mytype = self.boot_config["{s}/type".format(s=sect)]
        boot_menu.lines.append("")
        label = self.resolver.GetBootEntryString(sect, k_full_path)
        boot_menu.lines.append("menuentry \"{l}\" {{".format(l=label))

        # TODO: add last-selected, which is different than last-booted.
        #if self.config["boot/autopick"] == "last-booted":
        #	boot_menu.lines.append("    savedefault")

        # self.bootitems records all our boot items
        self.bootitems.append(label)

        scanpath = os.path.join(
            self.config.root_path,
            self.boot_config.item(sect, "scan").lstrip("/"))

        self.PrepareGRUBForFilesystem(scanpath, boot_menu.lines)

        # removes ROOT env var and /boot from the kernel path:
        k_sub_path = self.resolver.strip_mount_point(k_full_path)
        c = self.boot_config
        params = []
        if c.hasItem("boot/terminal") and c["boot/terminal"] == "serial":
            params += [
                "console=tty0",
                "console=ttyS%s,%s%s%s" %
                (c["serial/unit"], c["serial/speed"], c["serial/parity"][0],
                 c["serial/word"])
            ]
        for param in self.boot_config["{s}/params".format(s=sect)].split():
            if param not in params:
                params.append(param)

        # Logic here to see if we are processing a boot entry that is a kernel we should "attempt" to boot. It gets special parameters added to its boot
        # entry. It may be tagged by the user on this call to ego boot (user_specified_attempt_identifier) or we may simply have boot_menu.attempt_kname
        # set due to an attempted kernel having been selected previously:

        entry = boot_menu.addBootEntry(BootLoaderEntryType.LINUX,
                                       label=label,
                                       image_path=k_full_path)
        if BootMenuFlag.ATTEMPT in entry["flags"]:
            # Add special boot parameters for a kernel we are attempting to boot (usually panic=10 or similar to force a reboot)
            for param in self.boot_config["{s}/attemptparams".format(
                    s=sect)].split():
                if param not in params:
                    params.append(param)

        # TODO: turn off panic setting after successful boot? (ego boot success?)

        ok, myroot = self.resolver.calculate_rootfs_for_section(params)
        if not ok:
            return False
        ok, fstype = self.resolver.calculate_filesystem_for_section(params)
        if not ok:
            return False

        initrds = self.boot_config.item(sect, "initrd")
        initrds = self.resolver.find_initrds(initrds, scanpath, k_full_path,
                                             kext)
        if myroot and ('root=' + myroot) in params and 0 == len(initrds):
            params.remove('root=' + myroot)
            params.append('root=' + self.resolver.resolvedev(myroot))

        xenpath = None
        xenparams = None

        # Populate xen variables if type is xen
        if mytype == "xen":
            xenkernel = self.boot_config["{s}/xenkernel".format(s=sect)]
            # Add leading / if needed
            if not xenkernel.startswith("/"):
                xenkernel = "/{xker}".format(xker=xenkernel)
            xenpath = self.resolver.strip_mount_point(xenkernel)
            xenparams = self.boot_config["{s}/xenparams".format(
                s=sect)].split()

        # Add unique identifier that can be used to determine if kernel booted.
        params.append("rand_id=%s" % self.resolver.idmapper.get(k_full_path))
        # Append kernel lines based on type
        if mytype == "xen":
            boot_menu.lines.append("  multiboot {xker} {xparams}".format(
                xker=xenpath, xparams=" ".join(xenparams)))
            boot_menu.lines.append("  module {ker} {params}".format(
                ker=k_sub_path, params=" ".join(params)))
            for initrd in initrds:
                boot_menu.lines.append("  module {initrd}".format(
                    initrd=self.resolver.strip_mount_point(initrd)))
        else:
            boot_menu.lines.append("  {t} {k} {par}".format(
                t=mytype, k=k_sub_path, par=" ".join(params)))
            if initrds:
                initrds = (self.resolver.strip_mount_point(initrd)
                           for initrd in initrds)
                boot_menu.lines.append(
                    "  initrd {rds}".format(rds=" ".join(initrds)))

        # Append graphics line
        if self.boot_config.hasItem("{s}/gfxmode".format(s=sect)):
            skipgfx = False
            for p in params:
                if p.startswith("vga=") or p.startswith("video=uvesafb:"):
                    skipgfx = True
                    break
            if not skipgfx:
                boot_menu.lines.append("  set gfxpayload=keep")
        boot_menu.lines.append("}")

        return ok
コード例 #11
0
ファイル: grub.py プロジェクト: palica/ego
 def generateOtherBootEntry(self, boot_menu: BootLoaderMenu, sect) -> bool:
     """ Generates the boot entry for other systems """
     mytype = self.boot_config["{s}/type".format(s=sect)].lower()
     if mytype in ["dos", "msdos"]:
         mytype = "dos"
     elif mytype in [
             "windows", "windows 2000", "win2000", "windows xp", "winxp"
     ]:
         mytype = "winxp"
     elif mytype in ["windows vista", "vista"]:
         mytype = "vista"
     elif mytype in ["windows 7", "win7"]:
         mytype = "win7"
     elif mytype in ["windows 8", "win8"]:
         mytype = "win8"
     elif mytype in ["windows 10", "win10"]:
         mytype = "win10"
     elif mytype in ["haiku", "haiku os"]:
         mytype = "haiku"
     elif mytype in ["linux16"]:
         mytype = "linux16"
     else:
         self.msgs.append([
             "fatal",
             "Unrecognized boot entry type \"{mt}\"".format(mt=mytype)
         ])
         return False
     params = self.boot_config["{s}/params".format(s=sect)].split()
     myroot = self.resolver.GetParam(params, "root=")
     mychainloader = self.resolver.GetParam(params, "chainloader=")
     myname = sect
     # TODO check for valid root entry
     boot_menu.lines.append("")
     boot_menu.lines.append("menuentry \"{mn}\" {{".format(mn=myname))
     if mytype in ["linux16"]:
         k = self.resolver.strip_mount_point(self.boot_config[sect +
                                                              "/kernel"])
         full_k = os.path.join(self.boot_config["boot/path"], k.lstrip("/"))
         if not os.path.exists(full_k):
             self.msgs.append([
                 "warn",
                 "Image for section {sect} not found - {full_k}".format(
                     sect=sect, full_k=full_k)
             ])
         else:
             self.bootitems.append(myname)
             boot_menu.lines.append("  linux16 " + k)
     else:
         # TODO: add entry to boot_menu object
         self.PrepareGRUBForDevice(myroot, boot_menu.lines)
         self.bootitems.append(myname)
         self.DeviceGRUB(myroot)
         if mytype in ["win7", "win8"
                       ] or mytype == "win10" and self.uefiboot is False:
             boot_menu.lines.append(
                 "  chainloader " + mychainloader
             ) if mychainloader else boot_menu.lines.append(
                 "  chainloader +4")
         elif mytype in ["vista", "dos", "winxp", "haiku"]:
             boot_menu.lines.append(
                 "  chainloader " + mychainloader
             ) if mychainloader else boot_menu.lines.append(
                 "  chainloader +1")
         elif mytype in ["win10"]:
             boot_menu.lines.append(
                 "  chainloader " + mychainloader
             ) if mychainloader else boot_menu.lines.append(
                 "  chainloader /EFI/Microsoft/Boot/bootmgfw.efi")
     boot_menu.lines.append("}")
     boot_menu.addBootEntry(BootLoaderEntryType.OTHER, label=myname)
     return True
コード例 #12
0
ファイル: resolver.py プロジェクト: funtoo/ego
	def GenerateSections(self, boot_menu: BootLoaderMenu,
						 sfunc: Callable[[BootLoaderMenu, str, str], bool],
						 ofunc: Callable[[BootLoaderMenu, str], bool] = None) -> BootLoaderMenu:
		"""Generates sections using passed in extension-supplied functions"""
		try:
			timeout = int(self.boot_config["boot/timeout"])
		except ValueError:
			ok = False
			self.msgs.append(["fatal", "Invalid value for boot/timeout."])
			return boot_menu
		
		if timeout == 0:
			self.msgs.append(["warn", "boot/timeout value is zero - boot menu will not appear!"])
		elif timeout < 3:
			self.msgs.append(["norm", "boot/timeout value is below 3 seconds."])
		
		# Remove builtins from list of sections
		sections = self.boot_config.getSections()
		for sect in sections[:]:
			if sect in self.boot_config.builtins:
				sections.remove(sect)
		
		# If we have no boot entries, throw an error - force user to be
		# explicit.
		if len(sections) == 0:
			self.msgs.append(["fatal", "No boot entries are defined in /etc/boot.conf."])
			boot_menu.success = False
			return boot_menu
		
		# Warn if there are no linux entries
		has_linux = False
		for sect in sections:
			if self.boot_config["{s}/{t}".format(s=sect, t="type")] == "linux":
				has_linux = True
				break
		if has_linux is False:
			self.msgs.append(["warn", "No Linux boot entries are defined. You may not be able to re-enter Linux."])
		
		# Generate sections
		for sect in sections:
			if self.boot_config["{s}/type".format(s=sect)] in ["linux", "xen"]:
				ok = self._GenerateLinuxSection(boot_menu, sect, sfunc)
			elif ofunc:
				ok = self._GenerateOtherSection(boot_menu, sect, ofunc)
		
		if self._pos == 0:
			# this means we processed no kernels -- so we have nothing to boot!
			self.msgs.append(["fatal", "No matching kernels or boot entries found in /etc/boot.conf."])
			boot_menu.success = False
			return boot_menu
		elif boot_menu.default_position is None:
			# this means we didn't pick a default kernel to boot!
			self.msgs.append(["warn", "Had difficulty finding a default kernel -- using first one."])
			# If we didn't find a specified default, use the first one
			boot_menu.default_position = 0
		else:
			self.msgs.append(["note", "Default kernel selected via: %s." % self._default_mode])
			# Tag the boot menu as being default for display:
			boot_menu.boot_entries[boot_menu.default_position]["flags"].append(BootMenuFlag.DEFAULT)
		if self._default_mode == "autopick: mtime" and self.boot_config.item("boot", "autopick") == "last-booted":
				self.msgs.append(["warn", "Falling back to last modification time booting due to lack of last-booted info."])

		return boot_menu
コード例 #13
0
ファイル: resolver.py プロジェクト: funtoo/ego
	def _GenerateLinuxSection(self,
							  boot_menu: BootLoaderMenu,
							  sect: str,
							  sfunc: Callable[[BootLoaderMenu, str, str, str], bool]) -> bool:
		"""Generates section for Linux systems"""
		ok = True
		# Process a section, such as "genkernel" section.
		
		findlist, skiplist = self.boot_config.flagItemList("{s}/kernel".format(s=sect))
		
		# findlist == special patterns to match (i.e. kernel[-v])
		# skiplist == patterns to skip.
		
		findmatch = []
		skipmatch = []
		
		scanpaths = self.boot_config.item(sect, "scan").split()
		for scanpath in scanpaths:
			scanpath = os.path.join(self.config.root_path, scanpath.lstrip("/"))
			if self.config.root_path == "/":
				self.mount_if_necessary(scanpath)
			if len(skiplist):
				# find kernels to skip...
				matches = self.GetMatchingKernels(scanpath, skiplist)
				skipmatch += matches
			if len(findlist):
				# find kernels to match (skipping any kernels we should skip...)
				matches = self.GetMatchingKernels(scanpath, findlist, skipmatch)
				findmatch += matches
		
		# Generate individual boot entry using extension-supplied function
		
		found_multi = False
		
		# logic for finding a kernel to boot, based on default setting:
		# sort by modification time:
		findmatch = sorted(findmatch, key=lambda x: x[2], reverse=True)
		
		if self._default_mode == "autopick: mtime":
			# pick newest kernel by mtime, which happens to be top-of-list
			boot_menu.default_position = 0
			for kname, kext, mtime in findmatch:
				self._defnames.append(kname)
				ok = sfunc(boot_menu, sect, kname, kext)
				self._pos += 1

		else:
			def_mtime = None
			for kname, kext, mtime in findmatch:
				if (self._default == sect) or (self._default == kname) or (self._default == os.path.basename(kname)):
					# default match
					if boot_menu.default_position is not None:
						found_multi = True
						if mtime > def_mtime:
							# this kernel is newer, use it instead
							boot_menu.default_position = self._pos
							def_mtime = mtime
					else:
						boot_menu.default_position = self._pos
						def_mtime = os.stat(kname)[8]
				self._defnames.append(kname)
				ok = sfunc(boot_menu, sect, kname, kext)
				if not ok:
					break
				self._pos += 1
			
			if found_multi:
				self.msgs.append(["warn", "multiple matches found for default \"{name}\" - most recent used.".format(name=self._default)])

		return ok