1439 lines
61 KiB
Python
1439 lines
61 KiB
Python
#/**
|
|
#@file BootLib.py
|
|
#@brief Librería o clase Boot
|
|
#@class Boot
|
|
#@brief Funciones para arranque y post-configuración de sistemas de archivos.
|
|
#@warning License: GNU GPLv3+
|
|
#*/
|
|
|
|
import os
|
|
import re
|
|
import tempfile
|
|
import subprocess
|
|
import shutil
|
|
import glob
|
|
import inspect
|
|
|
|
import ogGlobals
|
|
import SystemLib
|
|
import FileSystemLib
|
|
import RegistryLib
|
|
import DiskLib
|
|
import InventoryLib
|
|
import FileLib
|
|
import UEFILib
|
|
import CacheLib
|
|
|
|
#/**
|
|
# ogBoot int_ndisk int_nfilesys [ NVRAMPERM ] [str_kernel str_initrd str_krnlparams]
|
|
#@brief Inicia el proceso de arranque de un sistema de archivos.
|
|
#@param int_ndisk nº de orden del disco
|
|
#@param int_nfilesys nº de orden del sistema de archivos
|
|
#@param str_nvramperm UEFI: La entrada en la NVRAM se incluye en el orden de arranque (opcional)
|
|
#@param str_krnlparams parámetros de arranque del kernel (opcional)
|
|
#@return (activar el sistema de archivos).
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo.
|
|
#@exception OG_ERR_PARTITION Tipo de partición desconocido o no se puede montar.
|
|
#@exception OG_ERR_NOTOS La partición no tiene instalado un sistema operativo.
|
|
#@note En Linux, si no se indican los parámetros de arranque se detectan de la opción por defecto del cargador GRUB.
|
|
#@note En Linux, debe arrancarse la partición del directorio \c /boot
|
|
#*/ ##
|
|
|
|
|
|
#/**
|
|
# ogGetWindowsName int_ndisk int_nfilesys
|
|
#@brief Muestra el nombre del equipo en el registro de Windows.
|
|
#@param int_ndisk nº de orden del disco
|
|
#@param int_nfilesys nº de orden del sistema de archivos
|
|
#@return str_name - nombre del equipo
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo.
|
|
#@exception OG_ERR_PARTITION Tipo de partición desconocido o no se puede montar.
|
|
#*/ ##
|
|
def ogGetWindowsName (disk, par):
|
|
mntdir = FileSystemLib.ogMount (disk, par)
|
|
if not mntdir: return None
|
|
|
|
# Obtener dato del valor de registro.
|
|
return RegistryLib.ogGetRegistryValue (mntdir, 'system', r'\ControlSet001\Control\ComputerName\ComputerName\ComputerName')
|
|
|
|
|
|
#/**
|
|
# ogLinuxBootParameters int_ndisk int_nfilesys
|
|
#@brief Muestra los parámetros de arranque de un sistema de archivos Linux.
|
|
#@param int_ndisk nº de orden del disco
|
|
#@param int_nfilesys nº de orden del sistema de archivos
|
|
#@return str_kernel str_initrd str_parameters ...
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo.
|
|
#@exception OG_ERR_PARTITION Tipo de partición desconocido o no se puede montar.
|
|
#@warning Función básica usada por \c ogBoot
|
|
#*/ ##
|
|
def ogLinuxBootParameters (disk, par):
|
|
# Detectar id. de tipo de partición y codificar al mnemonico.
|
|
mntdir = FileSystemLib.ogMount (disk, par)
|
|
if not mntdir: return None
|
|
|
|
# Fichero de configuración de GRUB.
|
|
confdir = mntdir # Sistema de archivos de arranque (/boot).
|
|
if os.path.isdir (f'{mntdir}/boot'):
|
|
confdir = f'{mntdir}/boot' # Sist. archivos raíz con directorio boot.
|
|
## original bash code:
|
|
## $MNTDIR/{,boot/}{{grubMBR,grubPARTITION}/boot/,}{grub{2,},{,efi/}EFI/*}/{menu.lst,grub.cfg}; do
|
|
conffile = None
|
|
for _uno in ['', 'boot']:
|
|
for _dos in ['grubMBR/boot', 'grubPARTITION/boot', '']:
|
|
for _tres in ['grub', 'grub2', 'EFI/*', 'efi/EFI/*']:
|
|
for _cuatro in ['menu.lst', 'grub.cfg']:
|
|
path = '/'.join ([mntdir, _uno, _dos, _tres, _cuatro])
|
|
if os.path.exists (path):
|
|
conffile = path
|
|
if not conffile:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, 'grub.cfg')
|
|
return None
|
|
|
|
# Toma del fichero de configuracion los valores del kernel, initrd
|
|
# y parámetros de arranque usando las cláusulas por defecto
|
|
# ("default" en GRUB1, "set default" en GRUB2)
|
|
# y los formatea para que sean compatibles con \c kexec . */
|
|
awk_script = '''BEGIN {cont=-1;}
|
|
$1~/^default$/ {sub(/=/," "); def=$2;}
|
|
$1~/^set$/ && $2~/^default/ { gsub(/[="]/," "); def=$3;
|
|
if (def ~ /saved_entry/) def=0;
|
|
}
|
|
$1~/^(title|menuentry)$/ {cont++}
|
|
$1~/^set$/ && $2~/^root=.\\(hd__DISK__,(msdos|gpt)__PAR__\\).$/ { if (def==0) def=cont; }
|
|
$1~/^(kernel|linux(16|efi)?)$/ { if (def==cont) {
|
|
kern=$2;
|
|
sub($1,""); sub($1,""); sub(/^[ \\t]*/,""); app=$0
|
|
}
|
|
}
|
|
$1~/^initrd(16|efi)?$/ {if (def==cont) init=$2}
|
|
END {if (kern!="") printf("%s %s %s", kern,init,app)}
|
|
'''
|
|
awk_script = awk_script.replace ('__DISK__', str (int (disk) - 1))
|
|
awk_script = awk_script.replace ('__PAR__', par)
|
|
awk_out = subprocess.run (['awk', awk_script, conffile], capture_output=True, text=True).stdout
|
|
return awk_out
|
|
|
|
|
|
#/**
|
|
# ogSetWindowsName int_ndisk int_nfilesys str_name
|
|
#@brief Establece el nombre del equipo en el registro de Windows.
|
|
#@param int_ndisk nº de orden del disco
|
|
#@param int_nfilesys nº de orden del sistema de archivos
|
|
#@param str_name nombre asignado
|
|
#@return (nada)
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo.
|
|
#@exception OG_ERR_PARTITION Tipo de partición desconocido o no se puede montar.
|
|
#@exception OG_ERR_OUTOFLIMIT Nombre Netbios con más de 15 caracteres.
|
|
#*/ ##
|
|
def ogSetWindowsName (disk, par, name):
|
|
if len (name) > 15:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_OUTOFLIMIT, f'"{name[0:15]}..."')
|
|
return
|
|
|
|
mntdir = FileSystemLib.ogMount (disk, par)
|
|
if not mntdir: return None
|
|
|
|
RegistryLib.ogSetRegistryValue (mntdir, 'system', r'\ControlSet001\Control\ComputerName\ComputerName\ComputerName', name)
|
|
RegistryLib.ogSetRegistryValue (mntdir, 'system', r'\ControlSet001\Services\Tcpip\Parameters\Hostname', name)
|
|
RegistryLib.ogSetRegistryValue (mntdir, 'system', r'\ControlSet001\Services\Tcpip\Parameters\HostName', name)
|
|
RegistryLib.ogSetRegistryValue (mntdir, 'system', r'\ControlSet001\services\Tcpip\Parameters\Hostname', name)
|
|
RegistryLib.ogSetRegistryValue (mntdir, 'system', r'\ControlSet001\Services\Tcpip\Parameters\NV Hostname', name)
|
|
RegistryLib.ogSetRegistryValue (mntdir, 'system', r'\ControlSet001\Services\Tcpip\Parameters\NV HostName', name)
|
|
RegistryLib.ogSetRegistryValue (mntdir, 'system', r'\ControlSet001\services\Tcpip\Parameters\NV Hostname', name)
|
|
|
|
|
|
|
|
#/**
|
|
# ogSetWinlogonUser int_ndisk int_npartition str_username
|
|
#@brief Establece el nombre de usuario por defecto en la entrada de Windows.
|
|
#@param int_ndisk nº de orden del disco
|
|
#@param int_npartition nº de orden de la partición
|
|
#@param str_username nombre de usuario por defecto
|
|
#@return (nada)
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo.
|
|
#@exception OG_ERR_PARTITION Tipo de partición desconocido o no se puede montar.
|
|
#*/ ##
|
|
def ogSetWinlogonUser (disk, par, username):
|
|
mntdir = FileSystemLib.ogMount (disk, par)
|
|
if not mntdir: return None
|
|
RegistryLib.ogSetRegistryValue (mntdir, 'SOFTWARE', r'\Microsoft\Windows NT\CurrentVersion\Winlogon\DefaultUserName', username)
|
|
|
|
|
|
#/**
|
|
# ogBootMbrXP int_ndisk
|
|
#@brief Genera un nuevo Master Boot Record en el disco duro indicado, compatible con los SO tipo Windows
|
|
#@param int_ndisk nº de orden del disco
|
|
#@return salida del programa my-sys
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_PARTITION Tipo de partición desconocido o no se puede montar.
|
|
#*/ ##
|
|
|
|
def ogBootMbrXP (disk):
|
|
DISK = DiskLib.ogDiskToDev (disk)
|
|
if not DISK: return None
|
|
subprocess.run (['ms-sys', '-z', '-f', DISK])
|
|
subprocess.run (['ms-sys', '-m', '-f', DISK])
|
|
|
|
#/**
|
|
# ogBootMbrGeneric int_ndisk
|
|
#@brief Genera un nuevo Codigo de arranque en el MBR del disco indicado, compatible con los SO tipo Windows, Linux.
|
|
#@param int_ndisk nº de orden del disco
|
|
#@return salida del programa my-sys
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Tipo de partición desconocido o no se puede montar.
|
|
#*/ ##
|
|
|
|
def ogBootMbrGeneric (disk):
|
|
DISK = DiskLib.ogDiskToDev (disk)
|
|
if not DISK: return None
|
|
subprocess.run (['ms-sys', '-z', '-f', DISK])
|
|
subprocess.run (['ms-sys', '-s', '-f', DISK])
|
|
|
|
# Firma necesaria para Windows equipos UEFI
|
|
with open ('/proc/sys/kernel/random/uuid', 'r') as fd:
|
|
kernel_random_uuid = fd.read().split ('-')[0]
|
|
signature = f'0x{kernel_random_uuid}'
|
|
subprocess.run (['ms-sys', '-S', signature, DISK])
|
|
|
|
|
|
|
|
#/**
|
|
# ogFixBootSector int_ndisk int_parition
|
|
#@brief Corrige el boot sector de una particion activa para MS windows/dos -fat-ntfs
|
|
#@param int_ndisk nº de orden del disco
|
|
#@param int_partition nº de particion
|
|
#@return
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_PARTITION Tipo de partición desconocido o no se puede montar.
|
|
#*/ ##
|
|
def ogFixBootSector (disk, par):
|
|
partype = DiskLib.ogGetPartitionId (disk, par)
|
|
if partype not in [ '1', '4', '6', '7', 'b', 'c', 'e', 'f', '17', '700', 'EF00' ]:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, '')
|
|
return
|
|
|
|
if not FileSystemLib.ogUnmount (disk, par):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, '')
|
|
return
|
|
|
|
disk0 = str (int (disk) - 1)
|
|
|
|
tmpfile = tempfile.NamedTemporaryFile (prefix='ogFBS-', mode='w').name
|
|
with open (tmpfile, 'w') as fd:
|
|
fd.write (f"""disk={disk0}
|
|
main_part={par}
|
|
fix_first_sector=yes
|
|
""")
|
|
subprocess.run (['timeout', '--foreground', '--signal=SIGKILL', '5s', 'spartlnx.run', '-cui', '-nm', '-w', '-f', tmpfile], stdin=subprocess.DEVNULL)
|
|
|
|
os.remove (tmpfile)
|
|
|
|
|
|
#/**
|
|
# ogGetBootMbr int_ndisk
|
|
#@brief Obtiene el contenido del sector de arranque de un disco.
|
|
#@param int_ndisk nº de orden del disco
|
|
#@return str_MBR Descripción del contenido del MBR.
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Dispositivo de disco no encontrado.
|
|
#*/ ##
|
|
def ogGetBootMbr (disk):
|
|
DISK = DiskLib.ogDiskToDev (disk)
|
|
if not DISK: return None
|
|
subprocess.run (['ms-sys', '-f', DISK])
|
|
|
|
#/**
|
|
# ogWindowsBootParameters int_ndisk int_parition
|
|
#@brief Configura el gestor de arranque de windows 7 / vista / XP / 2000
|
|
#@param int_ndisk nº de orden del disco
|
|
#@param int_partition nº de particion
|
|
#@return
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_PARTITION Tipo de partición desconocido o no se puede montar.
|
|
#*/ ##
|
|
|
|
def ogWindowsBootParameters (disk, par):
|
|
if not DiskLib.ogDiskToDev (disk, par):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, '')
|
|
return
|
|
|
|
disk0 = int (disk) - 1
|
|
|
|
tmpfile = tempfile.NamedTemporaryFile (prefix='ogWBP-', mode='w').name
|
|
if InventoryLib.ogIsEfiActive():
|
|
bootdisk, bootpar = DiskLib.ogGetEsp().split()
|
|
if not FileSystemLib.ogUnmount (bootdisk, bootpar):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, f'ESP: {bootdisk} {bootpar}')
|
|
return
|
|
bootdisk = str (int (bootdisk) - 1)
|
|
bootlabel = f'Part-{int(bootdisk):02d}-{int(bootpar):02d}'
|
|
bcdfile = f'boot_BCD_file=/EFI/{bootlabel}/Boot/BCD'
|
|
else:
|
|
bootdisk = disk0
|
|
bootpar = par
|
|
bcdfile = ''
|
|
|
|
|
|
# Obtener versión de Windows.
|
|
winver = InventoryLib.ogGetOsVersion (disk, par)
|
|
parts = re.split (':| ', winver)
|
|
if 'Windows' == parts[0] and 'Server' == parts[2]:
|
|
winver = parts[1] + parts[2] + parts[3]
|
|
else:
|
|
winver = parts[1] + parts[2]
|
|
if not winver:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTOS, 'Windows')
|
|
return
|
|
|
|
# Acciones para Windows XP.
|
|
if 'XP' in winver:
|
|
m = FileSystemLib.ogMount (disk, par)
|
|
if not m or not os.path.exists (f'{m}/boot.ini'):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, 'boot.ini')
|
|
return
|
|
with open (f'{m}/boot.ini', 'r') as fd:
|
|
boot_ini = fd.read()
|
|
boot_ini = re.sub (r'partition\([0-9]\)', f'partition({par})', boot_ini)
|
|
boot_ini = re.sub (r'rdisk\([0-9]\)', f'rdisk({disk0})', boot_ini)
|
|
with open (f'{m}/tmp.boot.ini', 'w') as fd:
|
|
fd.write (boot_ini)
|
|
os.rename (f'{m}/tmp.boot.ini', f'{m}/boot.ini')
|
|
return True
|
|
|
|
if not FileSystemLib.ogUnmount (disk, par):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, '')
|
|
return
|
|
|
|
|
|
#Preparando instruccion Windows Resume Application
|
|
with open (tmpfile, 'w') as fd:
|
|
fd.write (f"""boot_disk={bootdisk}
|
|
boot_main_part={bootpar}
|
|
{bcdfile}
|
|
disk={disk0}
|
|
main_part={par}
|
|
boot_entry=Windows Resume Application
|
|
""")
|
|
subprocess.run (['timeout', '--foreground', '--signal=SIGKILL', '5s', 'spartlnx.run', '-cui', '-nm', '-w', '-f', tmpfile], stdin=subprocess.DEVNULL)
|
|
|
|
|
|
#Preparando instruccion tipo windows
|
|
with open (tmpfile, 'w') as fd:
|
|
fd.write (f"""boot_disk={bootdisk}
|
|
boot_main_part={bootpar}
|
|
{bcdfile}
|
|
disk={disk0}
|
|
main_part={par}
|
|
boot_entry={winver}
|
|
""")
|
|
subprocess.run (['timeout', '--foreground', '--signal=SIGKILL', '5s', 'spartlnx.run', '-cui', '-nm', '-w', '-f', tmpfile], stdin=subprocess.DEVNULL)
|
|
|
|
##Preparando instruccion Ramdisk Options
|
|
with open (tmpfile, 'w') as fd:
|
|
fd.write (f"""boot_disk={bootdisk}
|
|
boot_main_part={bootpar}
|
|
{bcdfile}
|
|
disk={disk0}
|
|
main_part={par}
|
|
boot_entry=Ramdisk Options
|
|
""")
|
|
subprocess.run (['timeout', '--foreground', '--signal=SIGKILL', '5s', 'spartlnx.run', '-cui', '-nm', '-w', '-f', tmpfile], stdin=subprocess.DEVNULL)
|
|
|
|
##Preparando instruccion Recovery Environment
|
|
with open (tmpfile, 'w') as fd:
|
|
fd.write (f"""boot_disk={bootdisk}
|
|
boot_main_part={bootpar}
|
|
{bcdfile}
|
|
disk={disk0}
|
|
main_part={par}
|
|
boot_entry=Windows Recovery Environment
|
|
""")
|
|
subprocess.run (['timeout', '--foreground', '--signal=SIGKILL', '5s', 'spartlnx.run', '-cui', '-nm', '-w', '-f', tmpfile], stdin=subprocess.DEVNULL)
|
|
|
|
##Preparando instruccion Recovery
|
|
with open (tmpfile, 'w') as fd:
|
|
fd.write (f"""boot_disk={bootdisk}
|
|
boot_main_part={bootpar}
|
|
{bcdfile}
|
|
disk={disk0}
|
|
main_part={par}
|
|
boot_entry=Windows Recovery
|
|
""")
|
|
subprocess.run (['timeout', '--foreground', '--signal=SIGKILL', '5s', 'spartlnx.run', '-cui', '-nm', '-w', '-f', tmpfile], stdin=subprocess.DEVNULL)
|
|
|
|
#Preparando instruccion Windows Boot Manager
|
|
with open (tmpfile, 'w') as fd:
|
|
fd.write (f"""boot_disk={bootdisk}
|
|
boot_main_part={bootpar}
|
|
{bcdfile}
|
|
disk={bootdisk}
|
|
main_part={bootpar}
|
|
boot_entry=Windows Boot Manager
|
|
""")
|
|
subprocess.run (['timeout', '--foreground', '--signal=SIGKILL', '5s', 'spartlnx.run', '-cui', '-nm', '-w', '-f', tmpfile], stdin=subprocess.DEVNULL)
|
|
|
|
#Preparando instruccion Herramienta de diagnóstico de memoria de Windows
|
|
with open (tmpfile, 'w') as fd:
|
|
fd.write (f"""boot_disk={bootdisk}
|
|
boot_main_part={bootpar}
|
|
{bcdfile}
|
|
disk={bootdisk}
|
|
main_part={bootpar}
|
|
boot_entry=Herramienta de diagnóstico de memoria de Windows
|
|
""")
|
|
subprocess.run (['timeout', '--foreground', '--signal=SIGKILL', '5s', 'spartlnx.run', '-cui', '-nm', '-w', '-f', tmpfile], stdin=subprocess.DEVNULL)
|
|
|
|
#Preparando instruccion Herramienta de diagnóstico de memoria de Windows
|
|
with open (tmpfile, 'w') as fd:
|
|
fd.write (f"""boot_disk={bootdisk}
|
|
boot_main_part={bootpar}
|
|
{bcdfile}
|
|
disk={bootdisk}
|
|
main_part={bootpar}
|
|
boot_entry=Herramienta de diagn<f3>stico de memoria de Windows
|
|
""")
|
|
subprocess.run (['timeout', '--foreground', '--signal=SIGKILL', '5s', 'spartlnx.run', '-cui', '-nm', '-w', '-f', tmpfile], stdin=subprocess.DEVNULL)
|
|
|
|
os.remove (tmpfile)
|
|
|
|
|
|
|
|
#/**
|
|
# ogWindowsRegisterPartition int_ndisk int_partiton str_volume int_disk int_partition
|
|
#@brief Registra una partición en windows con un determinado volumen.
|
|
#@param int_ndisk nº de orden del disco a registrar
|
|
#@param int_partition nº de particion a registrar
|
|
#@param str_volumen volumen a resgistar
|
|
#@param int_ndisk_windows nº de orden del disco donde esta windows
|
|
#@param int_partition_windows nº de particion donde esta windows
|
|
#@return
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_PARTITION Tipo de partición desconocido o no se puede montar.
|
|
#*/ ##
|
|
#ogWindowsRegisterPartition ("1", "1", "c:", "1", "1")
|
|
def ogWindowsRegisterPartition (registered_disk, registered_par, registered_vol, disk, par):
|
|
registered_vol = registered_vol[0].upper()
|
|
tmpfile = tempfile.NamedTemporaryFile (prefix='ogWRP-', mode='w').name
|
|
|
|
if not DiskLib.ogDiskToDev (registered_disk, registered_par):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, 'particion a registrar')
|
|
return
|
|
|
|
if not DiskLib.ogDiskToDev (disk, par):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, 'particion de windows')
|
|
return
|
|
|
|
t = InventoryLib.ogGetOsType (disk, par)
|
|
if 'Windows' not in t:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTOS, 'no es windows')
|
|
return
|
|
|
|
v = InventoryLib.ogGetOsVersion (disk, par)
|
|
|
|
if FileLib.ogGetPath (src=f'{disk} {par}', file='WINDOWS'):
|
|
systemroot = 'Windows'
|
|
elif FileLib.ogGetPath (src=f'{disk} {par}', file='WINNT'):
|
|
systemroot = 'winnt'
|
|
else:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTOS, '')
|
|
return
|
|
|
|
FileSystemLib.ogUnmount (disk, par)
|
|
disk0 = str (int (disk) - 1)
|
|
registered_disk0 = str (int (registered_disk) - 1)
|
|
|
|
with open (tmpfile, 'w') as fd:
|
|
fd.write (f"""windows_disk={disk0}
|
|
windows_main_part={par}
|
|
windows_dir={systemroot}
|
|
disk={registered_disk0}
|
|
main_part={registered_par}
|
|
;ext_part
|
|
part_letter={registered_vol}
|
|
""")
|
|
subprocess.run (['timeout', '--foreground', '--signal=SIGKILL', '5s', 'spartlnx.run', '-cui', '-nm', '-w', '-f', tmpfile], stdin=subprocess.DEVNULL)
|
|
|
|
os.remove (tmpfile)
|
|
|
|
|
|
#/**
|
|
# ogGrubInstallMbr int_disk_GRUBCFG int_partition_GRUBCFG
|
|
#@brief Instala el grub el el MBR del primer disco duro (FIRSTSTAGE). El fichero de configuración grub.cfg ubicado según parametros disk y part(SECONDSTAGE). Admite sistemas Windows.
|
|
#@param int_disk_SecondStage
|
|
#@param int_part_SecondStage
|
|
#@param bolean_Check_Os_installed_and_Configure_2ndStage true | false[default]
|
|
#@return
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#*/ ##
|
|
|
|
#ogGrubInstallMbr ('1', '1', 'FALSE')
|
|
#ogGrubInstallMbr ('1', '1', 'TRUE', 'nomodeset irqpoll pci=noacpi quiet splash')
|
|
def ogGrubInstallMbr (disk, par, checkos='FALSE', kernelparam=''):
|
|
backupname = '.backup.og'
|
|
|
|
#error si no es linux.
|
|
#version = InventoryLib.ogGetOsVersion (disk, par)
|
|
#if not version or 'Linux' not in version:
|
|
# SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTOS, 'no es linux')
|
|
# return
|
|
|
|
firststage = DiskLib.ogDiskToDev ('1') #La primera etapa del grub se fija en el primer disco duro
|
|
secondstage = FileSystemLib.ogMount (disk, par) #localizar disco segunda etapa del grub
|
|
if not secondstage: return
|
|
os.makedirs (f'{secondstage}/boot/grub/', exist_ok=True)
|
|
prefixsecondstage = '/boot/grubMBR' #Localizar directorio segunda etapa del grub
|
|
efioptgrub = []
|
|
|
|
if InventoryLib.ogIsEfiActive():
|
|
esp = DiskLib.ogGetEsp()
|
|
efidisk, efipart = esp.split()
|
|
# Comprobamos que exista ESP y el directorio para ubuntu
|
|
efisecondstage = FileSystemLib.ogMount (efidisk, efipart)
|
|
if not efisecondstage:
|
|
FileSystemLib.ogFormat (efidisk, efipart, 'FAT32')
|
|
efisecondstage = FileSystemLib.ogMount (efidisk, efipart)
|
|
if not efisecondstage:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, 'ESP')
|
|
return
|
|
efisubdir = 'grub'
|
|
if os.path.isdir (f'{efisecondstage}/EFI/{efisubdir}'): # Borramos la configuración anterior
|
|
shutil.rmtree (f'{efisecondstage}/EFI/{efisubdir}')
|
|
os.makedirs (f'{efisecondstage}/EFI/{efisubdir}/Boot')
|
|
arch = InventoryLib.ogGetArch()
|
|
efioptgrub = ['--removable', '--no-nvram', '--uefi-secure-boot', '--target', f'{arch}-efi', f'--efi-directory={efisecondstage}/EFI/{efisubdir}']
|
|
|
|
# Si Reconfigurar segunda etapa (grub.cfg) == FALSE
|
|
if 'FALSE' == checkos.upper() and (os.path.exists (f'{secondstage}/boot/grub/grub.cfg') or os.path.exists (f'{secondstage}/boot/grub/grub.cfg{backupname}')):
|
|
if os.path.exists (f'{secondstage}/boot/grub/grub.cfg{backupname}'):
|
|
os.rename (f'{secondstage}/boot/grub/grub.cfg{backupname}', f'{secondstage}/boot/grub/grub.cfg')
|
|
if os.path.isdir (f'{secondstage}{prefixsecondstage}'):
|
|
shutil.rmtree (f'{secondstage}{prefixsecondstage}')
|
|
prefixsecondstage = '' # Reactivamos el grub con el grub.cfg original.
|
|
else: # SI Reconfigurar segunda etapa (grub.cfg) == TRUE
|
|
#llamada a updateBootCache para que aloje la primera fase del ogLive
|
|
subprocess.run ([f'{ogGlobals.OGSCRIPTS}/updateBootCache.py'], check=True)
|
|
|
|
if InventoryLib.ogIsEfiActive():
|
|
# UEFI: grubSintax necesita grub.cfg para detectar los kernels: si no existe recupero backup.
|
|
if not os.path.exists (f'{secondstage}/boot/grub/grub.cfg'):
|
|
if os.path.exists (f'{secondstage}/boot/grub/grub.cfg{backupname}'):
|
|
os.rename (f'{secondstage}/boot/grub/grub.cfg{backupname}', f'{secondstage}/boot/grub/grub.cfg')
|
|
else:
|
|
os.rename (f'{secondstage}/boot/grub/grub.cfg', f'{secondstage}/boot/grub/grub.cfg{backupname}')
|
|
|
|
with open ('/etc/default/grub', 'a') as fd: #Configur la sintaxis grub para evitar menus de "recovery" en el OGLive
|
|
fd.write ('GRUB_DISABLE_RECOVERY="true"\n')
|
|
fd.write ('GRUB_DISABLE_LINUX_UUID="true"\n')
|
|
|
|
os.makedirs (f'{secondstage}{prefixsecondstage}/boot/grub/', exist_ok=True) #Preparar configuración segunda etapa: crear ubicacion
|
|
subprocess.run (['sed', '-i', 's/^set -e/#set -e/', '/etc/grub.d/00_header']) #Preparar configuración segunda etapa: crear cabecera del fichero (ingnorar errores)
|
|
# (ogLive 5.0) Si 'pkgdatadir' está vacía ponemos valor de otros ogLive
|
|
subprocess.run (['sed', '-i', r'/grub-mkconfig_lib/i\pkgdatadir=${pkgdatadir:-"${datarootdir}/grub"}', '/etc/grub.d/00_header'])
|
|
out = subprocess.run (['/etc/grub.d/00_header'], capture_output=True, text=True).stdout
|
|
with open (f'{secondstage}{prefixsecondstage}/boot/grub/grub.cfg', 'w') as fd:
|
|
fd.write (out + '\n')
|
|
|
|
#Preparar configuración segunda etapa: crear entrada del sistema operativo
|
|
out = subprocess.run (['grubSyntax', kernelparam], capture_output=True, text=True).stdout
|
|
with open (f'{secondstage}{prefixsecondstage}/boot/grub/grub.cfg', 'a') as fd:
|
|
fd.write (out + '\n')
|
|
|
|
# Renombramos la configuración de grub antigua
|
|
if os.path.exists (f'{secondstage}/boot/grub/grub.cfg'):
|
|
os.rename (f'{secondstage}/boot/grub/grub.cfg', f'{secondstage}/boot/grub/grub.cfg{backupname}')
|
|
|
|
eval = subprocess.run (['grub-install', '--force'] + efioptgrub + [f'--root-directory={secondstage}{prefixsecondstage}', firststage]).returncode
|
|
|
|
if InventoryLib.ogIsEfiActive(): # Movemos el grubx64.efi
|
|
for b in (glob.glob (f'{efisecondstage}/EFI/{efisubdir}/EFI/BOOT/*')):
|
|
bn = os.path.basename (b)
|
|
os.rename (f'{efisecondstage}/EFI/{efisubdir}/EFI/BOOT/{bn}', f'{efisecondstage}/EFI/{efisubdir}/Boot/{bn}')
|
|
shutil.rmtree (f'{efisecondstage}/EFI/{efisubdir}/EFI')
|
|
shutil.copy2 ('/usr/lib/shim/shimx64.efi.signed', f'{efisecondstage}/EFI/{efisubdir}/Boot/shimx64.efi')
|
|
# Nombre OpenGnsys para cargador
|
|
shutil.copy2 (f'{efisecondstage}/EFI/{efisubdir}/Boot/grubx64.efi', f'{efisecondstage}/EFI/{efisubdir}/Boot/ogloader.efi')
|
|
|
|
# Creamos entrada NVRAM y la ponemos en segundo lugar
|
|
UEFILib.ogNvramAddEntry ('grub', '/EFI/grub/Boot/shimx64.efi')
|
|
grubentry = UEFILib.ogNvramList()
|
|
for l in grubentry.splitlines():
|
|
words = l.split()
|
|
if len(words) < 2: continue
|
|
if 'grub' == words[1]:
|
|
grubentry = words[0]
|
|
neworder = UEFILib.ogNvramGetOrder()
|
|
neworder = neworder[0:1] + [grubentry] + neworder[1:] ## la ponemos en segundo lugar
|
|
UEFILib.ogNvramSetOrder (neworder)
|
|
|
|
return eval
|
|
|
|
|
|
#/**
|
|
# ogGrubInstallPartition int_disk_SECONDSTAGE int_partition_SECONDSTAGE bolean_Check_Os_installed_and_Configure_2ndStage
|
|
#@brief Instala y actualiza el gestor grub en el bootsector de la particion indicada
|
|
#@param int_disk_SecondStage
|
|
#@param int_part_SecondStage
|
|
#@param bolean_Check_Os_installed_and_Configure_2ndStage true | false[default]
|
|
#@param str "kernel param "
|
|
#@return
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#*/ ##
|
|
|
|
#ogGrubInstallPartition ('1', '1', 'FALSE')
|
|
#ogGrubInstallPartition ('1', '1', 'TRUE', 'nomodeset irqpoll pci=noacpi quiet splash')
|
|
def ogGrubInstallPartition (disk, par, checkos='FALSE', kernelparam=''):
|
|
backupname = '.backup.og'
|
|
|
|
#error si no es linux.
|
|
version = InventoryLib.ogGetOsVersion (disk, par)
|
|
if not version or 'Linux' not in version:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTOS, 'no es linux')
|
|
return
|
|
|
|
firststage = DiskLib.ogDiskToDev (disk, par) #Localizar primera etapa del grub
|
|
secondstage = FileSystemLib.ogMount (disk, par) #localizar disco segunda etapa del grub
|
|
prefixsecondstage = '/boot/grubPARTITION' #Localizar directorio segunda etapa del grub
|
|
efioptgrub = []
|
|
|
|
if InventoryLib.ogIsEfiActive():
|
|
esp = DiskLib.ogGetEsp()
|
|
efidisk, efipart = esp.split()
|
|
# Comprobamos que exista ESP y el directorio para ubuntu
|
|
efisecondstage = FileSystemLib.ogMount (efidisk, efipart)
|
|
if not efisecondstage:
|
|
FileSystemLib.ogFormat (efidisk, efipart, 'FAT32')
|
|
efisecondstage = FileSystemLib.ogMount (efidisk, efipart)
|
|
if not efisecondstage:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, 'ESP')
|
|
return
|
|
efisubdir = f'Part-{int(disk):02d}-{int(par):02d}'
|
|
if os.path.isdir (f'{efisecondstage}/EFI/{efisubdir}'): # Borramos la configuración anterior
|
|
shutil.rmtree (f'{efisecondstage}/EFI/{efisubdir}')
|
|
os.makedirs (f'{efisecondstage}/EFI/{efisubdir}/Boot')
|
|
arch = InventoryLib.ogGetArch()
|
|
efioptgrub = ['--removable', '--no-nvram', '--uefi-secure-boot', '--target', f'{arch}-efi', f'--efi-directory={efisecondstage}/EFI/{efisubdir}']
|
|
|
|
# Si Reconfigurar segunda etapa (grub.cfg) == FALSE
|
|
if 'FALSE' == checkos.upper() and (os.path.exists (f'{secondstage}/boot/grub/grub.cfg') or os.path.exists (f'{secondstage}/boot/grub/grub.cfg{backupname}')):
|
|
if os.path.exists (f'{secondstage}/boot/grub/grub.cfg{backupname}'):
|
|
os.rename (f'{secondstage}/boot/grub/grub.cfg{backupname}', f'{secondstage}/boot/grub/grub.cfg')
|
|
if os.path.isdir (f'{secondstage}{prefixsecondstage}'):
|
|
shutil.rmtree (f'{secondstage}{prefixsecondstage}')
|
|
prefixsecondstage = '' # Reactivamos el grub con el grub.cfg original.
|
|
else: # SI Reconfigurar segunda etapa (grub.cfg) == TRUE
|
|
if InventoryLib.ogIsEfiActive():
|
|
# UEFI: grubSintax necesita grub.cfg para detectar los kernels: si no existe recupero backup.
|
|
if not os.path.exists (f'{secondstage}/boot/grub/grub.cfg'):
|
|
if os.path.exists (f'{secondstage}/boot/grub/grub.cfg{backupname}'):
|
|
os.rename (f'{secondstage}/boot/grub/grub.cfg{backupname}', f'{secondstage}/boot/grub/grub.cfg')
|
|
else:
|
|
if (os.path.exists (f'{secondstage}/boot/grub/grub.cfg')):
|
|
os.rename (f'{secondstage}/boot/grub/grub.cfg', f'{secondstage}/boot/grub/grub.cfg{backupname}')
|
|
|
|
with open ('/etc/default/grub', 'a') as fd: #Configur la sintaxis grub para evitar menus de "recovery" en el OGLive
|
|
fd.write ('GRUB_DISABLE_RECOVERY="true"\n')
|
|
fd.write ('GRUB_DISABLE_LINUX_UUID="true"\n')
|
|
|
|
os.makedirs (f'{secondstage}{prefixsecondstage}/boot/grub/', exist_ok=True) #Preparar configuración segunda etapa: crear ubicacion
|
|
subprocess.run (['sed', '-i', 's/^set -e/#set -e/', '/etc/grub.d/00_header']) #Preparar configuración segunda etapa: crear cabecera del fichero (ingnorar errores)
|
|
# (ogLive 5.0) Si 'pkgdatadir' está vacía ponemos valor de otros ogLive
|
|
subprocess.run (['sed', '-i', r'/grub-mkconfig_lib/i\pkgdatadir=${pkgdatadir:-"${datarootdir}/grub"}', '/etc/grub.d/00_header'])
|
|
out = subprocess.run (['/etc/grub.d/00_header'], capture_output=True, text=True).stdout
|
|
with open (f'{secondstage}{prefixsecondstage}/boot/grub/grub.cfg', 'w') as fd:
|
|
fd.write (out + '\n')
|
|
|
|
#Preparar configuración segunda etapa: crear entrada del sistema operativo
|
|
out = subprocess.run (['grubSyntax', disk, par, kernelparam], capture_output=True, text=True).stdout
|
|
with open (f'{secondstage}{prefixsecondstage}/boot/grub/grub.cfg', 'a') as fd:
|
|
fd.write (out + '\n')
|
|
|
|
#Instalar el grub
|
|
eval = subprocess.run (['grub-install', '--force'] + efioptgrub + [f'--root-directory={secondstage}{prefixsecondstage}', firststage]).returncode
|
|
|
|
# Movemos el grubx64.efi
|
|
if InventoryLib.ogIsEfiActive():
|
|
for b in (glob.glob (f'{efisecondstage}/EFI/{efisubdir}/EFI/BOOT/*')):
|
|
bn = os.path.basename (b)
|
|
os.rename (f'{efisecondstage}/EFI/{efisubdir}/EFI/BOOT/{bn}', f'{efisecondstage}/EFI/{efisubdir}/Boot/{bn}')
|
|
shutil.rmtree (f'{efisecondstage}/EFI/{efisubdir}/EFI')
|
|
shutil.copy2 ('/usr/lib/shim/shimx64.efi.signed', f'{efisecondstage}/EFI/{efisubdir}/Boot/shimx64.efi')
|
|
# Nombre OpenGnsys para cargador
|
|
shutil.copy2 (f'{efisecondstage}/EFI/{efisubdir}/Boot/grubx64.efi', f'{efisecondstage}/EFI/{efisubdir}/Boot/ogloader.efi')
|
|
|
|
return eval
|
|
|
|
|
|
|
|
#/**
|
|
# ogConfigureFstab int_ndisk int_nfilesys
|
|
#@brief Configura el fstab según particiones existentes
|
|
#@param int_ndisk nº de orden del disco
|
|
#@param int_nfilesys nº de orden del sistema de archivos
|
|
#@return (nada)
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND No se encuentra el fichero fstab a procesar.
|
|
#@warning Puede haber un error si hay más de 1 partición swap.
|
|
#*/ ##
|
|
def ogConfigureFstab (disk, par):
|
|
fstab = FileLib.ogGetPath (src=f'{disk} {par}', file='/etc/fstab')
|
|
if not fstab:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'{disk},{par},/etc/fstab')
|
|
return
|
|
|
|
efiopt = ''
|
|
|
|
shutil.copy2 (fstab, fstab+'.backup')
|
|
|
|
with open ('/etc/fstab', 'r') as fd:
|
|
while True:
|
|
l = fd.readline()
|
|
if not l: break
|
|
cosas = l.split()
|
|
if 6 != len (cosas): continue
|
|
fstab_dev, fstab_mntpt, fstab_fstype, fstab_opts, fstab_dump, fstab_pass = cosas
|
|
if '#' in fstab_dev: continue
|
|
if '/' == fstab_mntpt:
|
|
defroot = fstab_dev
|
|
elif 'swap' == fstab_fstype:
|
|
defswap = fstab_dev
|
|
elif '/boot/efi' == fstab_mntpt:
|
|
efiopt = '\t'.join ([fstab_fstype, fstab_opts, fstab_dump, fstab_pass])
|
|
|
|
partroot = DiskLib.ogDiskToDev (disk, par)
|
|
partswap = subprocess.run (['blkid', '-', ' TYPE=swap'], capture_output=True, text=True).stdout
|
|
if partswap:
|
|
partswap = partswap.splitlines()[0]
|
|
partswap = partswap.split (':')[0]
|
|
if defswap:
|
|
print ("Hay definicion de SWAP en el FSTAB $DEFSWAP -> modificamos fichero con nuevo valor $DEFSWAP->$PARTSWAP") # Mensaje temporal.
|
|
subprocess.run (f'sed "s|{defswap}|{partswap}|g; s|{defroot}|{partroot}|g" {fstab}.backup > {fstab}', shell=True)
|
|
else:
|
|
print ("No hay definicion de SWAP y si hay partición SWAP -> moficamos fichero") # Mensaje temporal.
|
|
subprocess.run (f'sed "s|{defroot}|{partroot}|g" {fstab}.backup > {fstab}', shell=True)
|
|
with open ('/etc/fstab', 'a') as fd:
|
|
fd.write (f'{partswap} none swap sw 0 0\n')
|
|
else:
|
|
print ("No hay partición SWAP -> configuramos FSTAB") # Mensaje temporal.
|
|
subprocess.run (f'sed "/swap/d" {fstab}.backup > {fstab}', shell=True)
|
|
# Si es un sistema EFI incluimos partición ESP (Si existe la modificamos)
|
|
if InventoryLib.ogIsEfiActive():
|
|
esp = DiskLib.ogGetEsp()
|
|
efidisk, efipart = esp.split()
|
|
efidev = DiskLib.ogDiskToDev (efidisk, efipart)
|
|
|
|
## Opciones de la partición ESP: si no existe ponemos un valor por defecto
|
|
if not efiopt:
|
|
efiopt = '\t'.join (['vfat', 'umask=0077', '0', '1'])
|
|
|
|
subprocess.run (f'sed -i /"boot\\/efi"/d {fstab}', shell=True)
|
|
with open ('/etc/fstab', 'a') as fd:
|
|
fd.write ('{efidev}\t/boot/efi\t{efiopt}\n')
|
|
|
|
|
|
|
|
#/**
|
|
# ogSetLinuxName int_ndisk int_nfilesys [str_name]
|
|
#@brief Establece el nombre del equipo en los ficheros hostname y hosts.
|
|
#@param int_ndisk nº de orden del disco
|
|
#@param int_nfilesys nº de orden del sistema de archivos
|
|
#@param str_name nombre asignado (opcional)
|
|
#@return (nada)
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo.
|
|
#@exception OG_ERR_PARTITION Tipo de partición desconocido o no se puede montar.
|
|
#@note Si no se indica nombre, se asigna un valor por defecto.
|
|
#*/ ##
|
|
def ogSetLinuxName (disk, par, hostname='pc'):
|
|
# Montar el sistema de archivos.
|
|
mntdir = FileSystemLib.ogMount (disk, par)
|
|
if not mntdir: return None
|
|
|
|
etc = FileLib.ogGetPath (src=f'{disk} {par}', file='/etc')
|
|
|
|
if os.path.isdir (etc):
|
|
#cambio de nombre en hostname
|
|
with open (f'{etc}/hostname', 'w') as fd:
|
|
fd.write (f'{hostname}\n')
|
|
#Opcion A para cambio de nombre en hosts
|
|
#sed "/127.0.1.1/ c\127.0.1.1 \t $HOSTNAME" $ETC/hosts > /tmp/hosts && cp /tmp/hosts $ETC/ && rm /tmp/hosts
|
|
#Opcion B componer fichero de hosts
|
|
with open (f'{etc}/hosts', 'w') as fd:
|
|
fd.write ('127.0.0.1 localhost\n')
|
|
fd.write (f'127.0.1.1 {hostname}\n')
|
|
fd.write ('\n')
|
|
fd.write ('# The following lines are desirable for IPv6 capable hosts\n')
|
|
fd.write ('::1 ip6-localhost ip6-loopback\n')
|
|
fd.write ('fe00::0 ip6-localnet\n')
|
|
fd.write ('ff00::0 ip6-mcastprefix\n')
|
|
fd.write ('ff02::1 ip6-allnodes\n')
|
|
fd.write ('ff02::2 ip6-allrouters\n')
|
|
|
|
|
|
|
|
#/**
|
|
# ogCleanLinuxDevices int_ndisk int_nfilesys
|
|
#@brief Limpia los dispositivos del equipo de referencia. Interfaz de red ...
|
|
#@param int_ndisk nº de orden del disco
|
|
#@param int_nfilesys nº de orden del sistema de archivos
|
|
#@return (nada)
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo.
|
|
#@exception OG_ERR_PARTITION Tipo de partición desconocido o no se puede montar.
|
|
#*/ ##
|
|
#ogCleanLinuxDevices (1, 1)
|
|
def ogCleanLinuxDevices (disk, par):
|
|
mntdir = FileSystemLib.ogMount (disk, par)
|
|
if not mntdir: return None
|
|
|
|
# Eliminar fichero de configuración de udev para dispositivos fijos de red.
|
|
if os.path.exists (f'{mntdir}/etc/udev/rules.d/70-persistent-net.rules'):
|
|
os.unlink (f'{mntdir}/etc/udev/rules.d/70-persistent-net.rules')
|
|
# Eliminar fichero resume (estado previo de hibernación) utilizado por el initrd scripts-premount
|
|
if os.path.exists (f'{mntdir}/etc/initramfs-tools/conf.d/resume'):
|
|
os.unlink ( f'{mntdir}/etc/initramfs-tools/conf.d/resume')
|
|
|
|
#/**
|
|
# ogGrubAddOgLive num_disk num_part [ timeout ] [ offline ]
|
|
#@brief Crea entrada de menu grub para ogclient, tomando como paramentros del kernel los actuales del cliente.
|
|
#@param 1 Numero de disco
|
|
#@param 2 Numero de particion
|
|
#@param 3 timeout Segundos de espera para iniciar el sistema operativo por defecto (opcional)
|
|
#@param 4 offline configura el modo offline [offline|online] (opcional)
|
|
#@return (nada)
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND No existe kernel o initrd en cache.
|
|
#@exception OG_ERR_NOTFOUND No existe archivo de configuracion del grub.
|
|
# /// FIXME: Solo para el grub instalado en MBR por Opengnsys, ampliar para más casos.
|
|
#*/ ##
|
|
|
|
|
|
def ogGrubAddOgLive (disk, par, timeout=None, offline=''):
|
|
oglivedir = os.environ.get ('oglivedir', 'ogLive')
|
|
# Error si no existe el kernel y el initrd en la cache.
|
|
# Falta crear nuevo codigo de error.
|
|
if not os.path.exists (f'{ogGlobals.OGCAC}/boot/{oglivedir}/ogvmlinuz') or not os.path.exists (f'{ogGlobals.OGCAC}/boot/{oglivedir}/oginitrd.img'):
|
|
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_NOTFOUND, 'CACHE: ogvmlinuz, oginitrd.img')
|
|
return None
|
|
|
|
# Archivo de configuracion del grub
|
|
dirmount = FileSystemLib.ogMount (disk, par)
|
|
grubcfg = f'{dirmount}/boot/grubMBR/boot/grub/grub.cfg'
|
|
|
|
# Error si no existe archivo del grub
|
|
if not os.path.exists (grubcfg):
|
|
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_NOTFOUND, grubcfg)
|
|
return None
|
|
|
|
# Si existe la entrada de opengnsys, se borra
|
|
grubcfg_contents = ''
|
|
with open (grubcfg, 'r') as fd:
|
|
grubcfg_contents = fd.read()
|
|
if 'menuentry Opengnsys' in grubcfg_contents:
|
|
subprocess.run (['sed', '-ie', '/menuentry Opengnsys/,+6d', grubcfg])
|
|
|
|
# Tipo de tabla de particiones
|
|
parttabletype = DiskLib.ogGetPartitionTableType (disk)
|
|
parttabletype = parttabletype.lower()
|
|
|
|
# Localizacion de la cache
|
|
cachepart = CacheLib.ogFindCache()
|
|
if not cachepart:
|
|
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_NOTCACHE, '')
|
|
return None
|
|
numdisk, numpart = cachepart.split()
|
|
numdisk = int (numdisk) - 1
|
|
# kernel y sus opciones. Pasamos a modo usuario
|
|
proc_cmdline = ''
|
|
with open ('/proc/cmdline', 'r') as fd:
|
|
proc_cmdline = fd.read().strip()
|
|
proc_cmdline = re.sub ('^.*linuz', '', proc_cmdline)
|
|
proc_cmdline = re.sub ('ogactiveadmin=[a-z]*', '', proc_cmdline)
|
|
kernel = f'/boot/{oglivedir}/ogvmlinuz {proc_cmdline}'
|
|
|
|
# Configuracion offline si existe parametro
|
|
STATUS = ''
|
|
if not offline: offline = ''
|
|
if 'offline' in offline: STATUS = 'offline'
|
|
if 'online' in offline: STATUS = 'online'
|
|
if STATUS:
|
|
kernel = re.sub ('ogprotocol=[a-z]* ', 'ogprotocol=local ', kernel)
|
|
kernel += f' ogstatus={STATUS}'
|
|
|
|
# Numero de línea de la primera entrada del grub.
|
|
grep_out = subprocess.run (['grep', '--line-number', '--max-count', '1', '^menuentry', grubcfg], capture_output=True, text=True).stdout
|
|
numline, _ = grep_out.split (':', maxsplit=1)
|
|
# Texto de la entrada de opengnsys
|
|
menuentry = f'''menuentry "OpenGnsys" --class opengnsys --class gnu --class os {{ \\
|
|
\tinsmod part_{parttabletype} \\
|
|
\tinsmod ext2 \\
|
|
\tset root='(hd{numdisk},{parttabletype}{numpart})' \\
|
|
\tlinux {kernel} \\
|
|
\tinitrd /boot/{oglivedir}/oginitrd.img \\
|
|
}}'''
|
|
|
|
|
|
# Insertamos la entrada de opengnsys antes de la primera entrada existente.
|
|
subprocess.run (['sed', '-i', f'{numline}i\\ {menuentry}', grubcfg])
|
|
|
|
# Ponemos que la entrada por defecto sea la primera.
|
|
subprocess.run (['sed', '-i', f's/set.*default.*$/set default="0"/g', grubcfg])
|
|
|
|
# Si me dan valor para timeout lo cambio en el grub.
|
|
if timeout:
|
|
subprocess.run (['sed', '-i', f's/timeout=.*$/timeout={timeout}/g', grubcfg])
|
|
|
|
#/**
|
|
# ogGrubHidePartitions num_disk num_part
|
|
#@brief ver ogBootLoaderHidePartitions
|
|
#@see ogBootLoaderHidePartitions
|
|
#*/ ##
|
|
def ogGrubHidePartitions (disk, par, datadisk=None, datapar=None):
|
|
return ogBootLoaderHidePartitions (disk, par, datadisk, datapar)
|
|
|
|
#/**
|
|
# ogBootLoaderHidePartitions num_disk num_part
|
|
#@brief Configura el grub/burg para que oculte las particiones de windows que no se esten iniciando.
|
|
#@param 1 Numero de disco
|
|
#@param 2 Numero de particion
|
|
#@param 3 Numero de disco de la partición de datos (no ocultar)
|
|
#@param 4 Numero de particion de datos (no ocultar)
|
|
#@return (nada)
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception No existe archivo de configuracion del grub/burg.
|
|
#*/
|
|
|
|
def ogBootLoaderHidePartitions (disk, par, datadisk=None, datapar=None):
|
|
# Nombre de la función que llama a esta.
|
|
func = inspect.stack()[1][3]
|
|
|
|
# Si no existe $4 pongo un valor imposible para la partición de datos
|
|
if datapar:
|
|
partdata = DiskLib.ogDiskToDev (datadisk, datapar)
|
|
else:
|
|
partdata = '0'
|
|
|
|
# Archivo de configuracion del grub
|
|
DIRMOUNT = FileSystemLib.ogMount (disk, par)
|
|
# La función debe ser llamanda desde ogGrubHidePartitions or ogBurgHidePartitions.
|
|
if 'ogGrubHidePartitions' == func:
|
|
cfgfile = f'{DIRMOUNT}/boot/grubMBR/boot/grub/grub.cfg'
|
|
else:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'Use ogGrubHidePartitions')
|
|
return None
|
|
|
|
# Error si no existe archivo del grub
|
|
if not os.path.exists (cfgfile):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, cfgfile)
|
|
return None
|
|
|
|
# Si solo hay una particion de Windows me salgo
|
|
num_ntfs = 0
|
|
disks = DiskLib.ogDiskToDev()
|
|
fdisk_out = subprocess.run (['fdisk', '-l']+disks, capture_output=True, text=True).stdout
|
|
for l in fdisk_out.splitlines():
|
|
if 'NTFS' in l: num_ntfs += 1
|
|
if 1 == num_ntfs: return True
|
|
|
|
# Elimino llamadas a parttool, se han incluido en otras ejecuciones de esta funcion.
|
|
subprocess.run (['sed', '-i', '/parttool/d', cfgfile])
|
|
|
|
parttabletype = DiskLib.ogGetPartitionTableType (disk)
|
|
parttabletype = parttabletype.lower()
|
|
|
|
# Entradas de Windows: numero de linea y particion. De mayor a menor.
|
|
#1:/dev/sda2
|
|
#2:/dev/sda3
|
|
awk_out = subprocess.run (f'''
|
|
awk '/menuentry.*Windows/ {{gsub(/\\)"/, ""); gsub(/^.*dev/,""); print NR":/dev"$1}} ' {cfgfile}
|
|
''', shell=True, text=True, capture_output=True).stdout
|
|
if awk_out:
|
|
winentry = awk_out.splitlines()
|
|
winentry.reverse()
|
|
else:
|
|
winentry = []
|
|
|
|
# Particiones de Windows, pueden no estar en el grub.
|
|
winpart = []
|
|
for l in fdisk_out.splitlines(): ## aprovechamos la variable fdisk_out de antes
|
|
if 'NTFS' not in l: continue
|
|
items = l.split (' ')
|
|
winpart.append (items[0])
|
|
winpart.reverse()
|
|
|
|
# Modifico todas las entradas de Windows.
|
|
for entry in winentry:
|
|
line, part = entry.split (':')
|
|
# En cada entrada, oculto o muestro cada particion.
|
|
text = ''
|
|
for parthidden in winpart:
|
|
# Muestro la particion de la entrada actual y la de datos.
|
|
if parthidden == part or parthidden == partdata:
|
|
hidden = '-'
|
|
else:
|
|
hidden = '+'
|
|
numdisk, numpart = DiskLib.ogDevToDisk (parthidden).split()
|
|
numdisk = int (numdisk)
|
|
numpart = int (numpart)
|
|
text = f'\tparttool (hd{numdisk-1},{parttabletype}{numpart}) hidden{hidden} \n{text}'
|
|
subprocess.run (['sed', '-i', f'{line}a\\ {text}', cfgfile])
|
|
# Activamos la particion que se inicia en todas las entradas de windows.
|
|
subprocess.run (['sed', '-i', '/chainloader/i\\\tparttool ${root} boot+', cfgfile])
|
|
#/**
|
|
# ogGrubDeleteEntry num_disk num_part num_disk_delete num_part_delete
|
|
#@brief ver ogBootLoaderDeleteEntry
|
|
#@see ogBootLoaderDeleteEntry
|
|
#*/
|
|
def ogGrubDeleteEntry (disk, par, diskdel, pardel):
|
|
return ogBootLoaderDeleteEntry (disk, par, diskdel, pardel)
|
|
|
|
#/**
|
|
# ogBootLoaderDeleteEntry num_disk num_part num_part_delete
|
|
#@brief Borra en el grub las entradas para el inicio en una particion.
|
|
#@param 1 Numero de disco donde esta el grub
|
|
#@param 2 Numero de particion donde esta el grub
|
|
#@param 3 Numero del disco del que borramos las entradas
|
|
#@param 4 Numero de la particion de la que borramos las entradas
|
|
#@note Tiene que ser llamada desde ogGrubDeleteEntry
|
|
#@return (nada)
|
|
#@exception OG_ERR_FORMAT Use ogGrubDeleteEntry
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND No existe archivo de configuracion del grub.
|
|
#*/ ##
|
|
|
|
def ogBootLoaderDeleteEntry (disk, par, diskdel, pardel):
|
|
# Nombre de la función que llama a esta.
|
|
func = inspect.stack()[1][3]
|
|
|
|
# Archivo de configuracion del grub
|
|
dirmount = FileSystemLib.ogMount (disk, par)
|
|
# La función debe ser llamanda desde ogGrubDeleteEntry, ogBurgDeleteEntry or ogRefindDeleteEntry.
|
|
if 'ogGrubDeleteEntry' == func:
|
|
cfgfile = f'{dirmount}/boot/grubMBR/boot/grub/grub.cfg'
|
|
else:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'Use ogGrubDeleteEntry')
|
|
return None
|
|
|
|
# Dispositivo
|
|
label = DiskLib.ogDiskToDev (diskdel, pardel)
|
|
|
|
# Error si no existe archivo de configuración
|
|
if not os.path.exists (cfgfile):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, cfgfile)
|
|
return None
|
|
|
|
# Numero de linea de cada entrada.
|
|
menuentry = []
|
|
grep_out = subprocess.run (['grep', '-n', '-e', 'menuentry', cfgfile], capture_output=True, text=True).stdout
|
|
if grep_out:
|
|
for l in grep_out.splitlines():
|
|
lineno, _ = l.split (':', maxsplit=1)
|
|
menuentry.append (lineno)
|
|
menuentry.reverse()
|
|
|
|
# Entradas que hay que borrar.
|
|
deleteentry = []
|
|
grep_out = subprocess.run (['grep', '-n', f'menuentry.*{label}', cfgfile], capture_output=True, text=True).stdout
|
|
if grep_out:
|
|
for l in grep_out.splitlines():
|
|
lineno, _ = l.split (':', maxsplit=1)
|
|
deleteentry.append (lineno)
|
|
|
|
# Si no hay entradas para borrar me salgo con aviso
|
|
if not deleteentry:
|
|
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_NOTFOUND, f'Menuentry {label}')
|
|
return None
|
|
|
|
# Recorremos el fichero del final hacia el principio.
|
|
with open (cfgfile, 'r') as fd:
|
|
endentry = len (fd.read().splitlines())
|
|
for entry in menuentry:
|
|
# Comprobamos si hay que borrar la entrada.
|
|
if entry in deleteentry:
|
|
endentry -= 1
|
|
subprocess.run (['sed', '-i', '-e', f'{entry},{endentry}d', cfgfile])
|
|
# Guardamos el número de línea de la entrada, que sera el final de la siguiente.
|
|
endentry = entry
|
|
#/**
|
|
# ogGrubDefaultEntry int_disk_GRUGCFG int_partition_GRUBCFG int_disk_default_entry int_npartition_default_entry
|
|
#@brief ver ogBootLoaderDefaultEntry
|
|
#@see ogBootLoaderDefaultEntry
|
|
#*/ ##
|
|
def ogGrubDefaultEntry (disk, par, diskdefault, pardefault):
|
|
return ogBootLoaderDefaultEntry (disk, par, diskdefault, pardefault)
|
|
|
|
#/**
|
|
# ogBootLoaderDefaultEntry int_disk_CFG int_partition_CFG int_disk_default_entry int_npartition_default_entry
|
|
#@brief Configura la entrada por defecto de Burg
|
|
#@param int_disk_SecondStage
|
|
#@param int_part_SecondStage
|
|
#@param int_disk_default_entry
|
|
#@param int_part_default_entry
|
|
#@return
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_PARTITION Partición errónea o desconocida (ogMount).
|
|
#@exception OG_ERR_OUTOFLIMIT Param $3 no es entero.
|
|
#@exception OG_ERR_NOTFOUND Fichero de configuración no encontrado: burg.cfg.
|
|
#*/ ##
|
|
def ogBootLoaderDefaultEntry (disk, par, diskdefault, pardefault):
|
|
# Nombre de la función que llama a esta.
|
|
func = inspect.stack()[1][3]
|
|
|
|
# Error si no puede montar sistema de archivos.
|
|
dirmount = FileSystemLib.ogMount (disk, par)
|
|
if not dirmount: return None
|
|
|
|
# Comprobamos que exista fichero de configuración
|
|
# La función debe ser llamanda desde ogGrubDefaultEntry, ogBurgDefaultEntry or ogRefindDefaultEntry.
|
|
if 'ogGrubDefaultEntry' == func:
|
|
cfgfile = f'{dirmount}/boot/grubMBR/boot/grub/grub.cfg'
|
|
else:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'Use ogGrubDefaultEntry')
|
|
return None
|
|
|
|
# Error si no existe archivo de configuración
|
|
if not os.path.exists (cfgfile):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, cfgfile)
|
|
return None
|
|
|
|
# Dispositivo
|
|
label = DiskLib.ogDiskToDev (diskdefault, pardefault)
|
|
|
|
# Número de línea de la entrada por defecto en CFGFILE (primera de la partición).
|
|
grep_out = subprocess.run (['grep', '--line-number', '--max-count', '1', f'menuentry.*{label}', cfgfile], capture_output=True, text=True).stdout
|
|
if not grep_out:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'menuentry {label}')
|
|
return None
|
|
defaultentry, _ = grep_out.split (':', maxsplit=1)
|
|
|
|
# Si no hay entradas para borrar me salgo con aviso
|
|
if not defaultentry:
|
|
SystemLib.ogRaiseError (['session', 'log'], ogGlobals.OG_ERR_NOTFOUND, f'No menuentry {label}')
|
|
return None
|
|
|
|
# Número de la de linea por defecto en el menú de usuario
|
|
menuentry = subprocess.run (f'grep -n -e menuentry {cfgfile}| cut -d: -f1 | grep -n {defaultentry} |cut -d: -f1', shell=True, text=True, capture_output=True).stdout
|
|
if not menuentry: return None
|
|
menuentry = int (menuentry)
|
|
# En grub y burg las líneas empiezan a contar desde cero
|
|
menuentry -= 1
|
|
subprocess.run (['sed', '--regexp-extended', '-i', f's/set default="?[0-9]*"?$/set default="{menuentry}"/g', cfgfile])
|
|
|
|
MSG = f'ogGlobals.lang.MSG_HELP_{func}'
|
|
try: MSG = eval (MSG)
|
|
except: MSG = ''
|
|
if '.' == MSG[-1]: MSG=MSG[0:-1]
|
|
print (f'{MSG}: {disk} {par} {diskdefault} {pardefault}')
|
|
return True
|
|
|
|
#/**
|
|
# ogGrubOgliveDefaultEntry num_disk num_part
|
|
#@brief ver ogBootLoaderOgliveDefaultEntry
|
|
#@see ogBootLoaderOgliveDefaultEntry
|
|
#*/ ##
|
|
def ogGrubOgliveDefaultEntry (disk, par):
|
|
return ogBootLoaderOgliveDefaultEntry (disk, par)
|
|
|
|
|
|
#/**
|
|
# ogBootLoaderOgliveDefaultEntry
|
|
#@brief Configura la entrada de ogLive como la entrada por defecto de Burg.
|
|
#@param int_disk_SecondStage
|
|
#@param int_part_SecondStage
|
|
#@return
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_PARTITION Partición errónea o desconocida (ogMount).
|
|
#@exception OG_ERR_NOTFOUND Fichero de configuración no encontrado: burg.cfg.
|
|
#@exception OG_ERR_NOTFOUND Entrada de OgLive no encontrada en burg.cfg.
|
|
#*/ ##
|
|
def ogBootLoaderOgliveDefaultEntry (disk, par):
|
|
# Nombre de la función que llama a esta.
|
|
func = inspect.stack()[1][3]
|
|
|
|
# Error si no puede montar sistema de archivos.
|
|
PART = FileSystemLib.ogMount (disk, par)
|
|
if not PART: return None
|
|
# La función debe ser llamanda desde ogGrubOgliveDefaultEntry, ogBurgOgliveDefaultEntry or ogRefindOgliveDefaultEntry.
|
|
if 'ogGrubOgliveDefaultEntry' == func:
|
|
cfgfile = f'{PART}/boot/grubMBR/boot/grub/grub.cfg'
|
|
else:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'Use ogGrubOgliveDefaultEntry')
|
|
return None
|
|
|
|
# Comprobamos que exista fichero de configuración
|
|
if not os.path.exists (cfgfile):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, cfgfile)
|
|
return None
|
|
|
|
# Detectamos cual es la entrada de ogLive
|
|
numentry = 0
|
|
with open (cfgfile, 'r') as fd:
|
|
while True:
|
|
l = fd.readline()
|
|
if not l: break
|
|
if l.startswith ('menuentry'):
|
|
numentry += 1
|
|
if 'OpenGnsys Live' in l: break
|
|
|
|
# Si no existe entrada de ogLive nos salimos
|
|
if not numentry:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'menuentry OpenGnsys Live in {cfgfile}')
|
|
return None
|
|
|
|
numentry -= 1
|
|
subprocess.run (['sed', '--regexp-extended', '-i', f's/set default="?[0-9]+"?/set default="{numentry}"/g', cfgfile])
|
|
|
|
MSG = f'ogGlobals.lang.MSG_HELP_{func}'
|
|
try: MSG = eval (MSG)
|
|
except: MSG = ''
|
|
if '.' == MSG[-1]: MSG=MSG[0:-1]
|
|
print (f'{MSG}: {disk} {par}')
|
|
return True
|
|
|
|
|
|
#/**
|
|
# ogGrubSecurity int_disk_GRUBCFG int_partition_GRUBCFG [user] [password]
|
|
#@brief Configura grub.cfg para que sólo permita editar entrada o acceder a línea de comandos al usuario especificado
|
|
#@param int_disk_SecondStage
|
|
#@param int_part_SecondStage
|
|
#@param user (default root)
|
|
#@param password (default "", no puede entrar)
|
|
#@return (nada)
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_PARTITION Tipo de partición desconocido o no se puede montar (ogMount).
|
|
#@exception OG_ERR_NOTFOUND No encuentra archivo de configuración del grub.
|
|
#*/ ##
|
|
def ogGrubSecurity (disk, par, user='root', passwd=''):
|
|
#localizar disco segunda etapa del grub
|
|
secondstage = FileSystemLib.ogMount (disk, par)
|
|
if not secondstage: return None
|
|
|
|
## original bash code:
|
|
## $SECONDSTAGE/{,boot/}{{grubMBR,grubPARTITION}/boot/,}{grub{,2},{,efi/}EFI/*}/{menu.lst,grub.cfg,grub.cfg.backup.og}
|
|
grubcfg = []
|
|
for _uno in ['', 'boot']:
|
|
for _dos in ['grubMBR/boot', 'grubPARTITION/boot', '']:
|
|
for _tres in ['grub', 'grub2', 'EFI/*', 'efi/EFI/*']:
|
|
for _cuatro in ['menu.lst', 'grub.cfg', 'grub.cfg.backup.og']:
|
|
path = '/'.join ([secondstage, _uno, _dos, _tres, _cuatro])
|
|
grubcfg += glob.glob (path)
|
|
print (f'nati grubcfg ({grubcfg})')
|
|
|
|
# comprobamos que exista el archivo de configuración.
|
|
if not grubcfg:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, 'grub.cfg')
|
|
return None
|
|
|
|
if passwd:
|
|
encryptpasswd = subprocess.run (['grub-mkpasswd-pbkdf2'], input=f'{passwd}\n{passwd}', text=True, capture_output=True).stdout
|
|
if encryptpasswd:
|
|
lines = encryptpasswd.strip().splitlines()
|
|
encryptpasswd = lines[-1]
|
|
encryptpasswd = re.sub ('^.*grub', 'grub', encryptpasswd)
|
|
|
|
for file in grubcfg:
|
|
# Eliminamos configuración anterior
|
|
subprocess.run (['sed', '-i', '-e', '/superusers/d', '-e', '/password_pbkdf2/d', file])
|
|
|
|
# Configuramos grub.cfg para que sólo permita editar o entrar en línea de comandos al usuario especificado
|
|
if passwd:
|
|
subprocess.run (['sed', '-i', f'1i\\password_pbkdf2 {user} {encryptpasswd}', file])
|
|
subprocess.run (['sed', '-i', f'1i\\set superusers="{user}"', file])
|
|
|
|
# Permitimos que se seleccionen las entradas
|
|
subprocess.run (['sed', '-i', '/menuentry /s/{/--unrestricted {/', file])
|
|
|
|
|
|
#/**
|
|
# ogGrubSetTheme num_disk num_part str_theme
|
|
#@brief ver ogBootLoaderSetTheme
|
|
#@see ogBootLoaderSetTheme
|
|
#*/ ##
|
|
|
|
|
|
#/**
|
|
# ogBootLoaderSetTheme
|
|
#@brief asigna un tema al BURG
|
|
#@param int_disk_SecondStage
|
|
#@param int_part_SecondStage
|
|
#@param str_theme_name
|
|
#@return
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_PARTITION Partición errónea o desconocida (ogMount).
|
|
#@exception OG_ERR_NOTFOUND Fichero de configuración no encontrado: grub.cfg burg.cfg refind.conf.
|
|
#@exception OG_ERR_NOTFOUND Entrada deltema no encontrada en burg.cfg.
|
|
#@exception OG_ERR_NOTFOUND Fichero de configuración del tema no encontrado: theme.conf (sólo refind).
|
|
#@note El tema debe situarse en OGLIB/BOOTLOADER/themes
|
|
#*/ ##
|
|
|
|
#/**
|
|
# ogGrubSetAdminKeys num_disk num_part str_theme
|
|
#@brief ver ogBootLoaderSetTheme
|
|
#@see ogBootLoaderSetTheme
|
|
#*/ ##
|
|
|
|
|
|
|
|
#/**
|
|
# ogBootLoaderSetAdminKeys
|
|
#@brief Activa/Desactica las teclas de administracion
|
|
#@param int_disk_SecondStage
|
|
#@param int_part_SecondStage
|
|
#@param Boolean TRUE/FALSE
|
|
#@return
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_PARTITION Partición errónea o desconocida (ogMount).
|
|
#@exception OG_ERR_NOTFOUND Fichero de configuración no encontrado: grub.cfg burg.cfg.
|
|
#@exception OG_ERR_NOTFOUND Entrada deltema no encontrada en burg.cfg.
|
|
#*/ ##
|
|
|
|
|
|
|
|
#/**
|
|
# ogGrubSetTimeOut num_disk num_part int_timeout_seconds
|
|
#@brief ver ogBootLoaderSetTimeOut
|
|
#@see ogBootLoaderSetTimeOut
|
|
#*/ ##
|
|
def ogGrubSetTimeOut (disk, par, timeout):
|
|
return ogBootLoaderSetTimeOut (disk, par, timeout)
|
|
|
|
#/**
|
|
# ogBootLoaderSetTimeOut
|
|
#@brief Define el tiempo (segundos) que se muestran las opciones de inicio
|
|
#@param int_disk_SecondStage
|
|
#@param int_part_SecondStage
|
|
#@param int_timeout_seconds
|
|
#@return
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_PARTITION Partición errónea o desconocida (ogMount).
|
|
#@exception OG_ERR_NOTFOUND Fichero de configuración no encontrado: grub.cfg burg.cfg.
|
|
#@exception OG_ERR_NOTFOUND Entrada deltema no encontrada en burg.cfg.
|
|
#*/ ##
|
|
def ogBootLoaderSetTimeOut (disk, par, timeout):
|
|
# Nombre de la función que llama a esta.
|
|
func = inspect.stack()[1][3]
|
|
|
|
# Error si no puede montar sistema de archivos.
|
|
PART = FileSystemLib.ogMount (disk, par)
|
|
if not PART: return None
|
|
# La función debe ser llamanda desde ogGrubSetTimeOut, ogBurgSetTimeOut or ogRefindSetTimeOut.
|
|
if 'ogGrubSetTimeOut' == func:
|
|
bootloader = 'grub'
|
|
bootloaderdir = 'boot/grubMBR'
|
|
cfgfile = f'{PART}/boot/grubMBR/boot/grub/grub.cfg'
|
|
else:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'Use ogGrubSetTimeOut')
|
|
return None
|
|
|
|
# Comprobamos que exista fichero de configuración
|
|
if not os.path.exists (cfgfile):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, cfgfile)
|
|
return None
|
|
|
|
# Asignamos el timeOut.
|
|
subprocess.run (['sed', '-i', f's/timeout=.*$/timeout={timeout}/g', cfgfile])
|
|
|
|
|
|
#/**
|
|
# ogGrubSetResolution num_disk num_part int_resolution
|
|
#@brief ver ogBootLoaderSetResolution
|
|
#@see ogBootLoaderSetResolution
|
|
#*/ ##
|
|
|
|
|
|
|
|
#/**
|
|
# ogBootLoaderSetResolution
|
|
#@brief Define la resolucion que usuara el thema del gestor de arranque
|
|
#@param int_disk_SecondStage
|
|
#@param int_part_SecondStage
|
|
#@param str_resolution (Opcional)
|
|
#@return
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_PARTITION Partición errónea o desconocida (ogMount).
|
|
#@exception OG_ERR_NOTFOUND Fichero de configuración no encontrado: grub.cfg burg.cfg.
|
|
#*/ ##
|
|
|
|
|
|
|
|
|
|
#/**
|
|
# ogBootLoaderSetResolution
|
|
#@brief Define la resolucion que usuara el thema del gestor de arranque
|
|
#@param int_resolution1
|
|
#@param int_resolution2 (Opcional)
|
|
#@return
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_PARTITION Partición errónea o desconocida (ogMount).
|
|
#@exception OG_ERR_NOTFOUND Fichero de configuración no encontrado: grub.cfg burg.cfg.
|
|
#*/ ##
|
|
|
|
#/**
|
|
# ogGrub4dosInstallMbr int_ndisk
|
|
#@brief Genera un nuevo Codigo de arranque en el MBR del disco indicado, compatible con los SO tipo Windows, Linux.
|
|
#@param int_ndisk nº de orden del disco
|
|
#@param int_ndisk nº de orden del particion
|
|
#@return
|
|
#@exception OG_ERR_FORMAT Formato incorrecto.
|
|
#@exception OG_ERR_NOTFOUND Tipo de partición desconocido o no se puede montar.
|
|
#@exception OG_ERR_NOTBIOS Equipo no firmware BIOS legacy
|
|
#@exception OG_ERR_NOMSDOS Disco duro no particioniado en modo msdos
|
|
#@exception OG_ERR_NOTWRITE Particion no modificable.
|
|
#*/ ##
|
|
|
|
def ogGrub4dosInstallMbr (disk, par):
|
|
#Controlar existencia de disco y particion
|
|
device = DiskLib.ogDiskToDev (disk)
|
|
if not device:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, '')
|
|
return None
|
|
mountdisk = FileSystemLib.ogMount (disk, par)
|
|
if not mountdisk:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, ogGlobals.lang.MSG_ERROR)
|
|
return None
|
|
#Controlar acceso de escritura a la particion
|
|
if FileSystemLib.ogIsReadonly (disk, par):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTWRITE, f': {disk} {par}')
|
|
return None
|
|
#Controlar disco no uefi
|
|
if InventoryLib.ogIsEfiActive():
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTBIOS, ' : grub4dos solo soporta PC con bios legacy')
|
|
return None
|
|
#Controlar particionado tipo msdos
|
|
ptt = DiskLib.ogGetPartitionTableType (disk)
|
|
if 'MSDOS' != ptt:
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOMSDOS, ': grub2dos requiere particionado tipo MSDOS')
|
|
return None
|
|
#Controlar la existencia del grub4dos con acceso a ntfs
|
|
bindir = f'{ogGlobals.OGLIB}/grub4dos/grub4dos-0.4.6a'
|
|
if not os.path.exists (f'{bindir}/bootlace.com'):
|
|
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f': {bindir}/bootlace.com')
|
|
return None
|
|
|
|
#instalar el bootloader de grlrd en el MBR
|
|
subprocess.run ([f'{bindir}/bootlace64.com', device], capture_output=True)
|
|
#copiar grld a la particion
|
|
shutil.copy2 (f'{bindir}/grldr', mountdisk)
|
|
#Instalar y configurar grub4dos
|
|
if os.path.exists (f'{mountdisk}/boot/grub/menu.lst'):
|
|
os.unlink (f'{mountdisk}/boot/grub/menu.lst')
|
|
os.rmdir (f'/{mountdisk}/boot/grub')
|
|
if not os.path.exists (f'{mountdisk}/boot/grub/menu.lst'):
|
|
os.makedirs (f'/{mountdisk}/boot/grub', exist_ok=True)
|
|
open (f'/{mountdisk}/boot/grub/menu.lst', 'w').close()
|
|
grubdisk = int (disk) - 1
|
|
with open (f'/{mountdisk}/boot/grub/menu.lst', 'w') as fd:
|
|
fd.write ('##NO-TOCAR-ESTA-LINEA MBR\n')
|
|
fd.write ('timeout 0\n')
|
|
fd.write ('title MBR\n')
|
|
fd.write (f'root (hd{grubdisk},0)\n')
|
|
fd.write (f'chainloader (hd{grubdisk},0)+1\n')
|
|
fd.write ('boot\n')
|
|
fd.write ('EOT\n')
|
|
fd.write ('\n')
|