from engine.SystemLib import * import subprocess import os import shutil def ogNvramActiveEntry(*args): FUNCNAME = ogNvramActiveEntry.__name__ NUMENTRY = None # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} [ Num_order_entry | Label_entry ]", f"{FUNCNAME} 2", f'{FUNCNAME} "Windows Boot Manager"') return # Error si no se recibe 1 parámetro. if len(args) != 1: ogRaiseError(OG_ERR_FORMAT, f"{FUNCNAME} [ Num_order_entry | Label_entry ]") return # Si no es equipo UEFI salir con error if not ogIsEfiActive(): ogRaiseError(OG_ERR_NOTUEFI) return # Distingo si es número de orden o etiqueta if args[0].isdigit(): NUMENTRY = subprocess.check_output(['efibootmgr', '-v']).decode().split()[0][4:8] else: NUMENTRY = subprocess.check_output(['efibootmgr', '-v']).decode().split()[0][4:8] if NUMENTRY == "": ogRaiseError(OG_ERR_NOTFOUND, f"NVRAM entry '{args[0]}'") return subprocess.run(['efibootmgr', '-a', '-b', NUMENTRY], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) def ogNvramAddEntry(*args): FUNCNAME = ogNvramAddEntry.__name__ EFIDISK = None EFIPART = None BOOTLABEL = None BOOTLOADER = None ADDORDER = None # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} Str_label_entry Str_boot_loader [ Bool_add_bootorder ]", f"{FUNCNAME} 1 2 TRUE", f'{FUNCNAME} grub /EFI/grub/grubx64.efi TRUE', f'{FUNCNAME} Windows /EFI/Microsoft/Boot/bootmgfw.efi') return # Error si no se recibe 2 o 3 parámetros. if len(args) < 2 or len(args) > 3: ogRaiseError(OG_ERR_FORMAT, f"{FUNCNAME} Str_label_entry Str_boot_loader") return # Si no es equipo UEFI salir con error if not ogIsEfiActive(): ogRaiseError(OG_ERR_NOTUEFI) return EFIDISK, EFIPART = ogGetEsp().split() if EFIPART == "": ogRaiseError(OG_ERR_NOTFOUND, "ESP") return # Recogemos parámetros # Distinguimos si es disco/partición o etiqueta/cargador if args[0].isdigit() and args[1].isdigit(): BOOTLABEL = f"Part-{int(args[0]):02d}-{int(args[1]):02d}" BOOTLOADER = f"/EFI/{BOOTLABEL}/Boot/ogloader.efi" else: BOOTLABEL = args[0] BOOTLOADER = args[1] # Si existe entrada con la misma etiqueta la borramos ogNvramDeleteEntry(BOOTLABEL) subprocess.run(['efibootmgr', '-C', '-d', ogDiskToDev(EFIDISK), '-p', EFIPART, '-L', BOOTLABEL, '-l', BOOTLOADER], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # Incluimos la entrada en el orden de arranque (opcional) if len(args) == 3 and args[2].upper() == "TRUE": NUMENTRY = subprocess.check_output(['efibootmgr']).decode().split('\n') for entry in NUMENTRY: if entry.startswith(BOOTLABEL): NUMENTRY = entry[4:8] break ogNvramSetOrder(*ogNvramGetOrder().split(','), NUMENTRY) def ogCopyEfiBootLoader(): FUNCNAME = ogCopyEfiBootLoader.__name__ # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} int_ndisk int_part", f"{FUNCNAME} 1 2") return # Error si no se reciben 2 parámetros. if len(args) != 2: ogRaiseError(OG_ERR_FORMAT, f"{FUNCNAME} int_ndisk int_part") return # Comprobamos que exista partición de sistema y la ESP MNTDIR = ogMount(args[0], args[1]) if MNTDIR is None: ogRaiseError(OG_ERR_PARTITION, f"{DISK} {PART}") return EFIDIR = ogMount(ogGetEsp()) if EFIDIR is None: ogRaiseError(OG_ERR_PARTITION, "ESP") return # Comprobamos que exista el cargador BOOTLABEL = f"Part-{int(args[0]):02d}-{int(args[1]):02d}" OSVERSION = ogGetOsVersion(args[0], args[1]) LOADER = None for f in [f"{EFIDIR}/EFI/Microsoft/Boot/bootmgfw.efi", f"{EFIDIR}/EFI/{BOOTLABEL}/Boot/bootmgfw.efi"]: if os.path.isfile(f): LOADER = f break if LOADER is None: ogRaiseError(OG_ERR_NOTOS, f"{args[0]} {args[1]} ({OSVERSION}, EFI)") return # Si existe el directorio Boot lo borramos if os.path.isdir(f"{MNTDIR}/ogBoot"): shutil.rmtree(f"{MNTDIR}/ogBoot") DIRLOADER = os.path.realpath(os.path.join(os.path.dirname(LOADER), "..")) shutil.copytree(f"{DIRLOADER}/Boot", f"{MNTDIR}/ogBoot") def ogNvramDeleteEntry(*args): FUNCNAME = ogNvramDeleteEntry.__name__ NUMENTRY = None # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} [ Num_order_entry | Label_entry ]", f"{FUNCNAME} 2", f'{FUNCNAME} "Windows Boot Manager"') return # Error si no se recibe 1 parámetro. if len(args) != 1: ogRaiseError(OG_ERR_FORMAT, f"{FUNCNAME} [ Num_order_entry | Label_entry ]") return # Si no es equipo UEFI salir con error if not ogIsEfiActive(): ogRaiseError(OG_ERR_NOTUEFI) return # Distingo si es número de orden o etiqueta if args[0].isdigit(): NUMENTRY = subprocess.check_output(['efibootmgr']).decode().split('\n') for entry in NUMENTRY: if entry.startswith(args[0]): NUMENTRY = entry[4:8] break else: NUMENTRY = subprocess.check_output(['efibootmgr']).decode().split('\n') for entry in NUMENTRY: if entry.startswith(args[0]): NUMENTRY = entry[4:8] break if NUMENTRY == "": ogRaiseError(OG_ERR_NOTFOUND, f"NVRAM entry '{args[0]}'") return for n in NUMENTRY: subprocess.run(['efibootmgr', '-B', '-b', n], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) def ogNvramGetCurrent(): FUNCNAME = ogNvramGetCurrent.__name__ # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, FUNCNAME, FUNCNAME) return # Si no es equipo UEFI salir con error if not ogIsEfiActive(): ogRaiseError(OG_ERR_NOTUEFI) return output = subprocess.check_output(['efibootmgr']).decode().split('\n') bootentry = 99999 for line in output: if "BootCurrent" in line: bootentry = line.split()[1] if bootentry in line: num_entry = line[4:8] label_entry = line[line.index(bootentry):] print(f"{num_entry} {label_entry}") def ogNvramGetNext(): # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, FUNCNAME, FUNCNAME) return # Si no es equipo UEFI salir con error if not ogIsEfiActive(): ogRaiseError(OG_ERR_NOTUEFI) return output = subprocess.check_output(['efibootmgr']).decode().split('\n') for line in output: if "BootNext" in line: bootnext = line.split()[1] return bootnext return None def ogNvramGetOrder(): FUNCNAME = ogNvramGetOrder.__name__ # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, FUNCNAME, FUNCNAME) return # Si no es equipo UEFI salir con error if not ogIsEfiActive(): ogRaiseError(OG_ERR_NOTUEFI) return output = subprocess.check_output(['efibootmgr']).decode().split('\n') for line in output: if "BootOrder" in line: bootorder = line.split(':')[1].strip() return bootorder return None def ogNvramGetTimeout(): FUNCNAME = ogNvramGetTimeout.__name__ # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, FUNCNAME, FUNCNAME) return # Si no es equipo UEFI salir con error if not ogIsEfiActive(): ogRaiseError(OG_ERR_NOTUEFI) return output = subprocess.check_output(['efibootmgr']).decode().split('\n') for line in output: if "Timeout" in line: timeout = line.split(':')[1].strip() return timeout return None def ogGrubUefiConf(*args): FUNCNAME = ogGrubUefiConf.__name__ EFIDIR = None BOOTLABEL = None GRUBEFI = None UUID = None DEVICE = None PREFIXSECONDSTAGE = None EFIGRUBDIR = None # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} int_ndisk int_part [ str_dir_grub ]", f"{FUNCNAME} 1 2", f"{FUNCNAME} 1 3 /boot/grubPARTITION") return # Error si no se reciben al menos 2 parámetros. if len(args) < 2: ogRaiseError(OG_ERR_FORMAT, f"{FUNCNAME} int_ndisk int_part [ str_dir_grub ]") return EFIDIR = ogMount(ogGetEsp()) if EFIDIR is None: ogRaiseError(OG_ERR_PARTITION, "ESP") return BOOTLABEL = f"Part-{int(args[0]):02d}-{int(args[1]):02d}" EFIGRUBDIR = f"{EFIDIR}/EFI/{BOOTLABEL}/boot/grub" # Comprobamos que existe directorio if not os.path.isdir(EFIGRUBDIR): os.makedirs(EFIGRUBDIR) # Parcheamos uuid y particion en grub.cfg UUID = subprocess.check_output(['blkid', '-o', 'value', '-s', 'UUID', ogDiskToDev(args[0], args[1])]).decode().strip() DEVICE = f"hd{int(args[0]) - 1},gpt{int(args[1])}" with open(f"{EFIGRUBDIR}/grub.cfg", "w") as f: f.write(f"set root='{DEVICE}'\n") f.write(f"set prefix=($root)'{args[2]}/boot/grub'\n") f.write(f"configfile $prefix/grub.cfg\n") # Provisional: confirmar si el segundo archivo se utiliza shutil.copy(f"{EFIGRUBDIR}/grub.cfg", f"{EFIDIR}/EFI/{BOOTLABEL}/grub.cfg") def ogNvramInactiveEntry(*args): FUNCNAME = ogNvramInactiveEntry.__name__ NUMENTRY = None # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} [ Num_order_entry | Label_entry ]", f"{FUNCNAME} 2", f'{FUNCNAME} "Windows Boot Manager"') return # Error si no se recibe 1 parámetro. if len(args) != 1: ogRaiseError(OG_ERR_FORMAT, f"{FUNCNAME} [ Num_order_entry | Label_entry ]") return # Si no es equipo UEFI salir con error if not ogIsEfiActive(): ogRaiseError(OG_ERR_NOTUEFI) return # Distingo si es número de orden o etiqueta if args[0].isdigit(): NUMENTRY = subprocess.check_output(['efibootmgr']).decode().split('\n') for entry in NUMENTRY: if entry.startswith(args[0]): NUMENTRY = entry[4:8] break else: NUMENTRY = subprocess.check_output(['efibootmgr']).decode().split('\n') for entry in NUMENTRY: if entry.startswith(args[0]): NUMENTRY = entry[4:8] break if NUMENTRY == "": ogRaiseError(OG_ERR_NOTFOUND, f"NVRAM entry '{args[0]}'") return subprocess.run(['efibootmgr', '-A', '-b', NUMENTRY], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) def ogNvramList(): FUNCNAME = ogNvramList.__name__ # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, FUNCNAME, FUNCNAME) return # Si no es equipo UEFI salir con error if not ogIsEfiActive(): ogRaiseError(OG_ERR_NOTUEFI) return output = subprocess.check_output(['efibootmgr']).decode().split('\n') for line in output: if line.startswith("Boot"): num_entry = line[4:8] label_entry = line[line.index(num_entry):] active = "*" if line.startswith("*") else "" print(f"{num_entry} {label_entry} {active}") def ogNvramPxeFirstEntry(): FUNCNAME = ogNvramPxeFirstEntry.__name__ NUMENTRY = None ORDER = None # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, FUNCNAME, FUNCNAME) return # Si no es equipo UEFI salir con error if not ogIsEfiActive(): ogRaiseError(OG_ERR_NOTUEFI) return NUMENTRY = subprocess.check_output(['efibootmgr']).decode().split('\n') for entry in NUMENTRY: if entry.startswith("IPv4"): NUMENTRY = entry[4:8] break # Si la entrada es la primera nos salimos. if NUMENTRY in ogNvramGetOrder().split(','): return # Si la entrada ya existe la borramos. ORDER = ogNvramGetOrder().split(',') if NUMENTRY in ORDER: ORDER.remove(NUMENTRY) ogNvramSetOrder(','.join([NUMENTRY] + ORDER)) def ogRestoreEfiBootLoader(*args): FUNCNAME = ogRestoreEfiBootLoader.__name__ MNTDIR = None EFIDIR = None BOOTLABEL = None OSVERSION = None LOADER = None UUID = None DEVICE = None # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} int_ndisk int_part", f"{FUNCNAME} 1 2") return # Error si no se reciben 2 parámetros. if len(args) != 2: ogRaiseError(OG_ERR_FORMAT, f"{FUNCNAME} int_ndisk int_part") return # Comprobamos que exista partición de sistema y la ESP MNTDIR = ogMount(args[0], args[1]) if MNTDIR is None: ogRaiseError(OG_ERR_PARTITION, f"{DISK} {PART}") return EFIDIR = ogMount(ogGetEsp()) if EFIDIR is None: ogFormat(ogGetEsp(), "FAT32") EFIDIR = ogMount(ogGetEsp()) if EFIDIR is None: ogRaiseError(OG_ERR_PARTITION, "ESP") return # Comprobamos que exista el cargador BOOTLABEL = f"Part-{int(args[0]):02d}-{int(args[1]):02d}" OSVERSION = ogGetOsVersion(args[0], args[1]) if "Windows" in OSVERSION: LOADER = ogGetPath(f"{MNTDIR}/ogBoot/bootmgfw.efi") if LOADER is None: ogRaiseError(OG_ERR_NOTOS, f"{args[0]} {args[1]} ({OSVERSION}, EFI)") return if os.path.isdir(f"{EFIDIR}/EFI/{BOOTLABEL}"): shutil.rmtree(f"{EFIDIR}/EFI/{BOOTLABEL}") os.makedirs(f"{EFIDIR}/EFI/{BOOTLABEL}") shutil.copytree(f"{LOADER.rstrip('/bootmgfw.efi')}", f"{EFIDIR}/EFI/{BOOTLABEL}/Boot") shutil.copy(LOADER, f"{EFIDIR}/EFI/{BOOTLABEL}/Boot/ogloader.efi") if os.path.isdir(f"{EFIDIR}/EFI/Microsoft"): os.rename(f"{EFIDIR}/EFI/Microsoft", f"{EFIDIR}/EFI/Microsoft.backup.og") def ogRestoreUuidPartitions(): FUNCNAME = ogRestoreUuidPartitions.__name__ DISK = None PART = None IMGNAME = None INFOFILE = None DEVICE = None DATA = None GUID = None UUID = None IMGGUID = None EFIDEVICE = None EFIDATA = None EFIGUID = None EFIUUID = None IMGEFIGUID = None # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} REPO|CACHE str_imgname int_ndisk int_npart", f"{FUNCNAME} REPO Windows 1 2") return # Error si no se reciben 4 parámetros. if len(args) != 4: ogRaiseError(OG_ERR_FORMAT, f"{FUNCNAME} REPO|CACHE str_imgname int_ndisk int_npart") return # Sólo se ejecuta si es UEFI if not ogIsEfiActive(): return # Parámetros de entrada IMGNAME = args[1] INFOFILE = f"{OGIMG}/.{IMGNAME}.img.json" if args[0].upper() == "CACHE": INFOFILE = f"{OGCAC}{INFOFILE}" # TODO: que la función getPath soporte archivos ocultos if not os.path.exists(INFOFILE): ogRaiseError(OG_ERR_NOTFOUND, INFOFILE) return DISK = args[2] PART = args[3] DEVICE = ogDiskToDev(DISK) EFIDISK, EFIPART = ogGetEsp().split() # Datos de la imagen IMGGUID = subprocess.check_output(['jq', '.guid', INFOFILE]).decode().strip().strip('"') IMGEFIGUID = subprocess.check_output(['jq', '.espguid', INFOFILE]).decode().strip().strip('"') # Datos actuales DATA = subprocess.check_output(['sfdisk', '-J', DEVICE]).decode() GUID = subprocess.check_output(['echo', DATA, '|', 'jq', '".partitiontable|.id"', '|', 'tr', '-d', '"']).decode().strip() if IMGGUID != GUID: subprocess.run(['sgdisk', '-U', IMGGUID, DEVICE]) subprocess.run(['partprobe']) if DISK == EFIDISK: EFIDATA = DATA EFIDEVICE = DEVICE else: EFIDEVICE = ogDiskToDev(EFIDISK) EFIDATA = subprocess.check_output(['sfdisk', '-J', EFIDEVICE]).decode() EFIGUID = subprocess.check_output(['echo', EFIDATA, '|', 'jq', '".partitiontable|.id"', '|', 'tr', '-d', '"']).decode().strip() if IMGEFIGUID != EFIGUID: subprocess.run(['sgdisk', '-U', IMGEFIGUID, EFIDEVICE]) subprocess.run(['partprobe']) def ogNvramSetNext(*args): FUNCNAME = ogNvramSetNext.__name__ NUMENTRY = None # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} [ Num_order_entry | Label_entry ]", f"{FUNCNAME} 2", f'{FUNCNAME} "Windows Boot Manager"') return # Error si no se recibe 1 parámetro. if len(args) != 1: ogRaiseError(OG_ERR_FORMAT, f"{FUNCNAME} [ Num_order_entry | Label_entry ]") return # Si no es equipo UEFI salir con error if not ogIsEfiActive(): ogRaiseError(OG_ERR_NOTUEFI) return # Distingo si es número de orden o etiqueta if args[0].isdigit(): NUMENTRY = subprocess.check_output(['efibootmgr']).decode().split('\n') for entry in NUMENTRY: if entry.startswith(args[0]): NUMENTRY = entry[4:8] break else: NUMENTRY = subprocess.check_output(['efibootmgr']).decode().split('\n') for entry in NUMENTRY: if entry.startswith(args[0]): NUMENTRY = entry[4:8] break if NUMENTRY == "": ogRaiseError(OG_ERR_NOTFOUND, f"NVRAM entry '{args[0]}'") return subprocess.run(['efibootmgr', '-n', NUMENTRY], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) def ogNvramSetOrder(*args): FUNCNAME = ogNvramSetOrder.__name # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} Num_order1 [ Num_order2 ] ...", f"{FUNCNAME} 1 3") return # Error si no se recibe al menos 1 parámetro. if len(args) < 1: ogRaiseError(OG_ERR_FORMAT, f"{FUNCNAME} Num_order1 [ Num_order2 ] ...") return # Si no es equipo UEFI salir con error if not ogIsEfiActive(): ogRaiseError(OG_ERR_NOTUEFI) return # Comprobamos que sean números for arg in args: if not arg.isdigit(): ogRaiseError(OG_ERR_FORMAT, f"{FUNCNAME} Num_order1 [ Num_order2 ] ...") return # Entradas de la NVRAM actuales NUMENTRYS = subprocess.check_output(['efibootmgr']).decode().split('\n') NUMENTRYS = [entry[4:8] for entry in NUMENTRYS if entry.startswith("Boot")] ORDER = "" for arg in args: # Si no existe la entrada me salgo if arg not in NUMENTRYS: ogRaiseError(OG_ERR_NOTFOUND, f"NVRAM entry order '{arg}'") return ORDER += f",{arg}" # Cambiamos el orden subprocess.run(['efibootmgr', '-o', ORDER[1:]], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) def ogNvramSetTimeout(*args): FUNCNAME = ogNvramSetTimeout.__name__ # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} int_Timeout (seg)", f"{FUNCNAME} 2") return # Si no es equipo UEFI salir con error if not ogIsEfiActive(): ogRaiseError(OG_ERR_NOTUEFI) return # Error si no se recibe 1 parámetro. if len(args) != 1: ogRaiseError(OG_ERR_FORMAT, f"{FUNCNAME} int_Timeout (seg)") return # Comprobamos que sea un número if not args[0].isdigit(): ogRaiseError(OG_ERR_FORMAT, f"{FUNCNAME} int_Timeout (seg)") return # Cambiamos el timeout subprocess.run(['efibootmgr', '-t', args[0]], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) def ogUuidChange(*args): FUNCNAME = ogUuidChange.__name__ MNTDIR = None DEVICE = None UUID = None NEWUUID = None # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} int_ndisk int_part", f"{FUNCNAME} 1 2") return # Error si no se reciben al menos 2 parámetros. if len(args) < 2: ogRaiseError(OG_ERR_FORMAT, f"{FUNCNAME} int_ndisk int_part") return # Comprobamos que exista la partición MNTDIR = ogMount(args[0], args[1]) if MNTDIR is None: ogRaiseError(OG_ERR_NOTFOUND, f"Device {args[0]} {args[1]}") return DEVICE = ogDiskToDev(args[0], args[1]) UUID = subprocess.check_output(['blkid', '-o', 'value', '-s', 'UUID', DEVICE]).decode().strip() NEWUUID = subprocess.check_output(['cat', '/proc/sys/kernel/random/uuid']).decode().strip() # Cambiamos UUID a la partición ogUnmount(args[0], args[1]) subprocess.run(['tune2fs', DEVICE, '-U', NEWUUID], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) # Cambiamos UUID en la configuración (fstab y grub) ogMount(args[0], args[1]) for f in [f"{MNTDIR}/etc/fstab", f"{MNTDIR}/{{,boot/}}{{grubMBR,grubPARTITION}}/boot/{{,grub{,2},{,efi/}EFI/*/}}/{{menu.lst,grub.cfg}}"]: if os.path.isfile(f): subprocess.run(['sed', '-i', f's/{UUID}/{NEWUUID}/g', f], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)