Compare commits
No commits in common. "main" and "filebeat" have entirely different histories.
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -5,36 +5,6 @@ All notable changes to this project will be documented in this file.
|
|||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [0.26.1] - 2025-07-14
|
||||
|
||||
### Changed
|
||||
|
||||
- Change sort order in `_getAllDisks()`
|
||||
|
||||
## [0.26.0] - 2025-07-14
|
||||
|
||||
### Fixed
|
||||
|
||||
- Overhaul partitioning
|
||||
|
||||
## [0.25.2] - 2025-07-14
|
||||
|
||||
### Fixed
|
||||
|
||||
- Run initCache.py rather than just initCache
|
||||
|
||||
## [0.25.1] - 2025-07-11
|
||||
|
||||
### Changed
|
||||
|
||||
- Derive a strong password from the default opengnsys weak one
|
||||
|
||||
## [0.25.0] - 2025-07-11
|
||||
|
||||
## Added
|
||||
|
||||
- Add ogGit functionality
|
||||
|
||||
## [0.24.0] - 2025-07-11
|
||||
|
||||
### Added
|
||||
|
|
|
@ -1,16 +1,15 @@
|
|||
#!/bin/bash
|
||||
|
||||
F=/etc/filebeat/filebeat.yml
|
||||
OPENSEARCH_PORT=9200
|
||||
OGLOG_PORT=9200
|
||||
|
||||
if [ -f $F ]; then
|
||||
PASS=$(grep "^[ ]*\(export \)\?OPTIONS=" /scripts/ogfunctions 2>&1 |sed 's/\(.*\)pass=\(\w*\)\(.*\)/\2/') ## taken from a sibling script
|
||||
PASS=${PASS:-"og"}
|
||||
PASS=OG+$(echo -n $PASS |sha256sum |cut -c1-12) ## og KDF
|
||||
chmod 0600 $F
|
||||
sed -i -e "s/__OGLOG_IP__/$oglog/g" \
|
||||
-e "s/__OGLOG_PORT__/$OPENSEARCH_PORT/g" \
|
||||
-e "s/__OPENSEARCH_PASSWORD__/$PASS/g" \
|
||||
sed -i -e "s/__OGLOG_IP__/$oglog/g" \
|
||||
-e "s/__OGLOG_PORT__/$OGLOG_PORT/g" \
|
||||
-e "s/__OPENSEARCH_PASSWORD__/$PASS/g" \
|
||||
$F
|
||||
unset PASS
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
import ogGlobals
|
||||
import SystemLib
|
||||
|
@ -33,12 +34,12 @@ prog = os.path.basename(__name__)
|
|||
#
|
||||
# El parámetro $2 es el que aporta toda la información y el $1 se queda obsoleto
|
||||
# Formato de entrada:
|
||||
# dis=Número de disco
|
||||
# != caracter de separación
|
||||
# dis=Número de disco
|
||||
# != caracter de separación
|
||||
#
|
||||
# Y un numero indeterminado de cadenas del tipo siguuenteseparadas por el caracter '$':
|
||||
# par=Número de particion*cod=Código de partición*sfi=Sistema de ficheros*tam=Tamaño de la partición*ope=Operación
|
||||
# @= caracter de separación
|
||||
# par=Número de particion*cod=Código de partición*sfi=Sistema de ficheros*tam=Tamaño de la partición*ope=Operación
|
||||
# @= caracter de separación
|
||||
#____________________________________________________________________
|
||||
|
||||
# Captura de parámetros (se ignora el 1er parámetro y se eliminan espacios y tabuladores).
|
||||
|
@ -50,13 +51,12 @@ param = sys.argv[2]
|
|||
tbprm = param.split ('!')
|
||||
pparam = tbprm[0] # General disk parameters
|
||||
sparam = tbprm[1] # Partitioning and formatting parameters
|
||||
is_there_cache = 'CACHE' in sparam
|
||||
|
||||
# Toma valores de disco y caché, separados por "*".
|
||||
# Los valores están en las variables $dis: disco, $che: existe cache (1, 0), $tch: Tamaño de la cache.
|
||||
pparams = pparam.split ('*')
|
||||
tbprm = pparam.split ('*')
|
||||
dis = tch = None
|
||||
for item in pparams:
|
||||
for item in tbprm:
|
||||
if '=' not in item: continue
|
||||
|
||||
k, v = item.split ('=', 1)
|
||||
|
@ -74,13 +74,10 @@ if dis is None:
|
|||
tbp = [] # Valores de configuración (parámetros para ogCreatePartitions)
|
||||
tbf = {} # Tabla de formateo
|
||||
|
||||
sparams = sparam.split('%')
|
||||
tbprm = sparam.split('%')
|
||||
|
||||
maxp=0
|
||||
sum_tam = 0
|
||||
do_sum_tam = True
|
||||
cache_seen = extended_seen = efi_seen = False
|
||||
for item in sparams:
|
||||
for item in tbprm:
|
||||
if not item: continue ## por si nos pasan un '%' al final de todo
|
||||
# Leer datos de la partición, separados por "*".
|
||||
par = cpt = sfi = tam = None
|
||||
|
@ -96,7 +93,7 @@ for item in sparams:
|
|||
if 'par' == k: par = int (v)
|
||||
elif 'cpt' == k: cpt = v
|
||||
elif 'sfi' == k: sfi = v
|
||||
elif 'tam' == k: tam = int (v)
|
||||
elif 'tam' == k: tam = v
|
||||
elif 'ope' == k: ope = int (v)
|
||||
|
||||
missing_params = []
|
||||
|
@ -109,29 +106,10 @@ for item in sparams:
|
|||
sys.exit (1)
|
||||
|
||||
# Componer datos de particionado.
|
||||
if 'EFI' == cpt:
|
||||
if efi_seen:
|
||||
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_FORMAT, f'se ha solicitado más de una partición de ESP')
|
||||
sys.exit (1)
|
||||
efi_seen = True
|
||||
if 'CACHE' == cpt:
|
||||
if cache_seen:
|
||||
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_FORMAT, f'se ha solicitado más de una partición de cache')
|
||||
sys.exit (1)
|
||||
cache_seen = True
|
||||
tch = tam
|
||||
else:
|
||||
tbp.append (f'{cpt}:{tam}')
|
||||
if do_sum_tam:
|
||||
sum_tam += tam
|
||||
if 'EXTENDED' == cpt:
|
||||
if extended_seen:
|
||||
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_FORMAT, f'se ha solicitado más de una partición extendida')
|
||||
sys.exit (1)
|
||||
extended_seen = True
|
||||
extended_is_at = par
|
||||
do_sum_tam = False ## don't sum sizes anymore
|
||||
|
||||
if ope:
|
||||
# Si se activa operación de formatear, componer datos de formateo.
|
||||
if cpt not in ['EMPTY', 'EXTENDED', 'LINUX-LVM', 'LVM', 'ZPOOL']:
|
||||
|
@ -140,88 +118,7 @@ for item in sparams:
|
|||
if par > maxp: maxp = par
|
||||
|
||||
if tch is None:
|
||||
tch = 0
|
||||
|
||||
|
||||
|
||||
|
||||
cur_ptt = DiskLib.ogGetPartitionTableType (dis)
|
||||
ptt = 'GPT' if InventoryLib.ogIsEfiActive() else 'MSDOS'
|
||||
|
||||
if not cache_seen and not tbp:
|
||||
SystemLib.ogRaiseError (['session', 'log'], ogGlobals.OG_ERR_FORMAT, f'No se ha solicitado ninguna partición')
|
||||
sys.exit (1)
|
||||
|
||||
if 'GPT' == ptt and extended_seen:
|
||||
SystemLib.ogRaiseError (['session', 'log'], ogGlobals.OG_ERR_FORMAT, f'En GPT no se pueden usar particiones extendidas')
|
||||
sys.exit (1)
|
||||
|
||||
## error si nos piden más de 4 y ninguna es extendida
|
||||
if 'MSDOS' == ptt and not extended_seen:
|
||||
requested_partitions = len (tbp)
|
||||
if cache_seen: requested_partitions += 1
|
||||
if requested_partitions > 4:
|
||||
SystemLib.ogRaiseError (['session', 'log'], ogGlobals.OG_ERR_FORMAT, f'Se han solicitado más de 4 particiones y ninguna es extendida')
|
||||
sys.exit (1)
|
||||
|
||||
if efi_seen:
|
||||
if 'EFI' != tbp[0].split (':')[0]:
|
||||
SystemLib.ogRaiseError (['session', 'log'], ogGlobals.OG_ERR_FORMAT, f'la partición ESP debe estar declarada en primera posición')
|
||||
sys.exit (1)
|
||||
else:
|
||||
if 'GPT' == ptt and 1 == dis:
|
||||
SystemLib.ogRaiseError (['session', 'log'], ogGlobals.OG_ERR_FORMAT, f'En GPT debe haber una partición ESP')
|
||||
sys.exit (1)
|
||||
|
||||
## si no nos definen partición de cache y el disco tiene una, hay que borrarla
|
||||
if not cache_seen:
|
||||
c = CacheLib.ogFindCache()
|
||||
if c:
|
||||
cache_disk, cache_part = c.split()
|
||||
if int (cache_disk) == int (dis):
|
||||
CacheLib.ogUnmountCache()
|
||||
CacheLib.ogDeleteCache()
|
||||
|
||||
## la extendida solo puede estar en la (si hay cache) o en la 4 (si no lo hay)
|
||||
if extended_seen:
|
||||
extended_should_be_at = 3 if cache_seen else 4
|
||||
if extended_is_at != extended_should_be_at:
|
||||
SystemLib.ogRaiseError (['session', 'log'], ogGlobals.OG_ERR_FORMAT, f'La partición extendida no puede ser la "{extended_is_at}" sino que debe ser la "{extended_should_be_at}"')
|
||||
sys.exit (1)
|
||||
|
||||
recreate_partition_table = False
|
||||
if not cur_ptt:
|
||||
SystemLib.ogEcho (['session', 'log'], None, f'No partition table--will create a "{ptt}" one')
|
||||
recreate_partition_table = True
|
||||
if cur_ptt and ptt != cur_ptt:
|
||||
SystemLib.ogEcho (['session', 'log'], None, f'Current partition table type "{cur_ptt}" is wrong for this system--will replace it for a "{ptt}" one')
|
||||
recreate_partition_table = True
|
||||
|
||||
## size check: check that cache fits in the space left by the previously existing partitions
|
||||
if not recreate_partition_table and not CacheLib.ogCheckNewCacheSize (dis, tch):
|
||||
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_CACHE, f'nueva partición de caché no cabe en el hueco actual')
|
||||
## BUG el "hueco actual" me podría dar igual, si luego resulta que también estoy definiendo otras particiones y ya sí hay sitio para todo
|
||||
sys.exit (1)
|
||||
|
||||
## size check: check that the newly defined partitions fit in the disk
|
||||
disk_sectors = DiskLib.ogGetLastSector (dis)
|
||||
IOSIZE = DiskLib.ogGetIoSize (dis)
|
||||
if not IOSIZE:
|
||||
SystemLib.ogRaiseError (['session', 'log'], ogGlobals.OG_ERR_FORMAT, f'Failed to get disk sector size')
|
||||
sys.exit (1)
|
||||
if 512 == IOSIZE:
|
||||
sum_tam_sectors = sum_tam*2
|
||||
cache_sectors = tch*2
|
||||
else:
|
||||
sum_tam_sectors = (sum_tam+3)//4 ## sumamos 3 para que la división entera "redondee al alza"
|
||||
cache_sectors = (tch+3)//4
|
||||
## esta comprobacion puede dejar pasar situaciones que más tarde dan error
|
||||
## la ventana es bastante estrecha, y sumando aquí simplemente un 1 por 1000, ya la cerramos del todo
|
||||
sum_tam_sectors = int (sum_tam_sectors * 1.001)
|
||||
space_left_by_cache = disk_sectors - cache_sectors
|
||||
if sum_tam_sectors > space_left_by_cache:
|
||||
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_CACHE, f'las particiones no caben en el disco')
|
||||
sys.exit (1)
|
||||
tch = '0'
|
||||
|
||||
#____________________________________________________
|
||||
#
|
||||
|
@ -236,46 +133,53 @@ SystemLib.ogEcho (['session', 'log'], None, f'[10] {ogGlobals.lang.MSG_HELP_ogUn
|
|||
FileSystemLib.ogUnmountAll (dis)
|
||||
CacheLib.ogUnmountCache()
|
||||
|
||||
if recreate_partition_table:
|
||||
# Elimina la tabla de particiones
|
||||
cur_ptt = DiskLib.ogGetPartitionTableType (dis)
|
||||
ptt = 'GPT' if InventoryLib.ogIsEfiActive() else 'MSDOS'
|
||||
if not cur_ptt or ptt != cur_ptt:
|
||||
DiskLib.ogDeletePartitionTable (dis)
|
||||
SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogUpdatePartitionTable'])
|
||||
DiskLib.ogCreatePartitionTable (dis, ptt)
|
||||
|
||||
# Inicia la cache.
|
||||
if is_there_cache:
|
||||
if 'CACHE' in sparam:
|
||||
SystemLib.ogEcho (['session', 'log'], None, f'[30] {ogGlobals.lang.MSG_HELP_ogCreateCache}')
|
||||
SystemLib.ogEcho (['session', 'log'], None, f' initCache.py {dis} {tch}')
|
||||
rc = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGSCRIPTS}/initCache.py', str (dis), str (tch)])
|
||||
SystemLib.ogEcho (['session', 'log'], None, f' initCache {tch}')
|
||||
rc = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGSCRIPTS}/initCache', tch])
|
||||
if not rc:
|
||||
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_CACHE, f'initCache.py failed')
|
||||
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_CACHE, f'initCache failed')
|
||||
sys.exit (1)
|
||||
|
||||
# Definir particionado.
|
||||
if tbp:
|
||||
SystemLib.ogEcho (['session', 'log'], None, f'[50] {ogGlobals.lang.MSG_HELP_ogCreatePartitions}')
|
||||
SystemLib.ogEcho (['session', 'log'], None, f' ogCreatePartitions {dis} {' '.join (tbp)}')
|
||||
res = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogCreatePartitions', str(dis)] + tbp)
|
||||
if not res:
|
||||
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_FORMAT, f'ogCreatePartitions {dis} {' '.join (tbp)}')
|
||||
sys.exit (1)
|
||||
SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogUpdatePartitionTable'])
|
||||
SystemLib.ogEcho (['session', 'log'], None, f'[50] {ogGlobals.lang.MSG_HELP_ogCreatePartitions}')
|
||||
SystemLib.ogEcho (['session', 'log'], None, f' ogCreatePartitions {dis} {' '.join (tbp)}')
|
||||
res = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogCreatePartitions', str(dis)] + tbp)
|
||||
if not res:
|
||||
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_GENERIC, f'ogCreatePartitions {dis} {' '.join (tbp)}')
|
||||
sys.exit (1)
|
||||
SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogUpdatePartitionTable'])
|
||||
|
||||
# Formatear particiones
|
||||
SystemLib.ogEcho (['session', 'log'], None, f'[70] {ogGlobals.lang.MSG_HELP_ogFormat}')
|
||||
retval = 0
|
||||
if tbf:
|
||||
# Formatear particiones
|
||||
SystemLib.ogEcho (['session', 'log'], None, f'[70] {ogGlobals.lang.MSG_HELP_ogFormat}')
|
||||
for p in range (1, maxp+1):
|
||||
if p not in tbf: continue
|
||||
if 'CACHE' == tbf[p]:
|
||||
if CACHESIZE == tch: # Si el tamaño es distinto ya se ha formateado.
|
||||
SystemLib.ogEcho (['session', 'log'], None, ' ogFormatCache')
|
||||
retval = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogFormatCache'])
|
||||
else:
|
||||
SystemLib.ogEcho (['session', 'log'], None, f' ogFormatFs {dis} {p} {tbf[p]}')
|
||||
retval = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogFormatFs', str(dis), str(p), tbf[p]])
|
||||
if not retval:
|
||||
SystemLib.ogRaiseError (['session', 'log'], ogGlobals.OG_ERR_GENERIC, f'ogFormatFs {dis} {p} {tbf[p]}')
|
||||
sys.exit (1)
|
||||
|
||||
for p in range (1, maxp+1):
|
||||
if p not in tbf: continue
|
||||
if 'CACHE' == tbf[p]:
|
||||
if CACHESIZE == tch: # Si el tamaño es distinto ya se ha formateado.
|
||||
SystemLib.ogEcho (['session', 'log'], None, ' ogFormatCache')
|
||||
retval = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogFormatCache'])
|
||||
else:
|
||||
SystemLib.ogEcho (['session', 'log'], None, f' ogFormatFs {dis} {p} {tbf[p]}')
|
||||
retval = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogFormatFs', str(dis), str(p), tbf[p]])
|
||||
if not retval:
|
||||
SystemLib.ogRaiseError (['session', 'log'], ogGlobals.OG_ERR_GENERIC, f'ogFormatFs {dis} {p} {tbf[p]}')
|
||||
sys.exit (1)
|
||||
# Registro de fin de ejecución
|
||||
SystemLib.ogEcho (['session', 'log'], None, f'{ogGlobals.lang.MSG_INTERFACE_END} {retval}')
|
||||
|
||||
#___________________________________________________________________
|
||||
#
|
||||
# Retorno
|
||||
#___________________________________________________________________
|
||||
|
||||
sys.exit (0)
|
||||
|
|
|
@ -1,78 +1,36 @@
|
|||
#!/usr/bin/env python3
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import resource
|
||||
import logging
|
||||
import time
|
||||
|
||||
|
||||
sys.path.insert(0, "/opt/oglive/rootfs/opt/opengnsys/lib/python3/")
|
||||
sys.path.insert(0, "/opt/opengnsys/interfaceAdm/git/")
|
||||
sys.path.insert(0, "/opt/opengnsys/ogrepository/oggit/lib/")
|
||||
|
||||
import NetLib
|
||||
import ogGlobals
|
||||
import SystemLib
|
||||
import DiskLib
|
||||
import NetLib
|
||||
|
||||
|
||||
from GitLib import OpengnsysGitLibrary, NTFSImplementation, OgProgressPrinterWeb
|
||||
from gitlib import OpengnsysGitLibrary, NTFSImplementation
|
||||
|
||||
|
||||
def create_image(disk_num, partition_num, repo, image_name, tagName):
|
||||
def create_image(disk_num, partition_num, repo, image_name):
|
||||
|
||||
ntfs_impl = NTFSImplementation.NTFS3G
|
||||
og_git = OpengnsysGitLibrary(ntfs_implementation = ntfs_impl)
|
||||
og_git.progress_callback = OgProgressPrinterWeb()
|
||||
|
||||
device = DiskLib.ogDiskToDev(disk_num, partition_num)
|
||||
if og_git.initRepo(device, image_name):
|
||||
return 0
|
||||
#if tagName:
|
||||
# og_git.tag(device = device, tagName = tagName, commit = "HEAD", message = "Image created")
|
||||
else:
|
||||
return 1
|
||||
|
||||
device = og_git._runBashFunction("ogDiskToDev", [str(disk_num), str(partition_num)])
|
||||
og_git.initRepo(device, image_name)
|
||||
|
||||
def main():
|
||||
|
||||
soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
|
||||
try:
|
||||
# Usamos el mínimo entre 65536 y el límite hard disponible
|
||||
new_limit = min(65536, hard)
|
||||
resource.setrlimit(resource.RLIMIT_NOFILE, (new_limit, hard))
|
||||
print(f"RLIMIT_NOFILE establecido a: {resource.getrlimit(resource.RLIMIT_NOFILE)}")
|
||||
except ValueError as e:
|
||||
print(f"No se pudo aumentar el límite de archivos abiertos: {e}")
|
||||
|
||||
|
||||
|
||||
if len(sys.argv) != 6:
|
||||
sys.exit(SystemLib.ogRaiseError([], ogGlobals.OG_ERR_FORMAT, "Incorrect number of arguments. Usage: CrearImagenGit.py disk_num partition_num image_name repo tag"))
|
||||
|
||||
# repo - repositorio, ip address. Opcional porque oglive lo recibe como parametro de kernel
|
||||
# tag - tag a crear automaticamente. Opcional, no necesitamos crear un tag siempre.
|
||||
|
||||
sys.exit(SystemLib.ogRaiseError(OG_ERR_FORMAT, "Incorrect number of arguments"))
|
||||
|
||||
disk_num, partition_num, image_name, repo, tag = sys.argv[1:6]
|
||||
|
||||
|
||||
opengnsys_log_dir = "/opt/opengnsys/log"
|
||||
ip_address = NetLib.ogGetIpAddress()
|
||||
logFilePath = f"{opengnsys_log_dir}/{ip_address}.log"
|
||||
|
||||
fileLog = logging.FileHandler(logFilePath)
|
||||
fileLog.setLevel(logging.DEBUG)
|
||||
|
||||
formatter = logging.Formatter('%(asctime)s - %(name)24s - [%(levelname)5s] - %(message)s')
|
||||
|
||||
fileLog.setFormatter(formatter)
|
||||
|
||||
logger = logging.getLogger(__package__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
logger.addHandler(fileLog)
|
||||
|
||||
logger.info("Starting CrearImagenGit")
|
||||
|
||||
|
||||
retval = create_image(disk_num, partition_num, repo, image_name, tag)
|
||||
|
||||
|
||||
retval = create_image(disk_num, partition_num, repo, image_name)
|
||||
|
||||
sys.exit(retval)
|
||||
|
||||
|
|
|
@ -1,96 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import resource
|
||||
|
||||
|
||||
|
||||
soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
|
||||
try:
|
||||
# Usamos el mínimo entre 65536 y el límite hard disponible
|
||||
new_limit = min(65536, hard)
|
||||
resource.setrlimit(resource.RLIMIT_NOFILE, (new_limit, hard))
|
||||
print(f"RLIMIT_NOFILE establecido a: {resource.getrlimit(resource.RLIMIT_NOFILE)}")
|
||||
except ValueError as e:
|
||||
print(f"No se pudo aumentar el límite de archivos abiertos: {e}")
|
||||
|
||||
# Añadir rutas personalizadas de forma segura
|
||||
extra_paths = [
|
||||
"/opt/opengnsys/interfaceAdm/git/",
|
||||
"/opt/opengnsys/ogrepository/oggit/lib/"
|
||||
]
|
||||
|
||||
|
||||
# Si estás completamente seguro de que esta ruta no interfiere con la stdlib
|
||||
# y contiene todos los módulos necesarios, puedes añadirla AL FINAL del path.
|
||||
path_maybe_problematic = "/opt/oglive/rootfs/opt/opengnsys/lib/python3/"
|
||||
if os.path.isdir(path_maybe_problematic):
|
||||
sys.path.append(path_maybe_problematic)
|
||||
|
||||
for path in extra_paths:
|
||||
if os.path.isdir(path):
|
||||
sys.path.append(path)
|
||||
|
||||
|
||||
import NetLib
|
||||
import ogGlobals
|
||||
import SystemLib
|
||||
import logging
|
||||
import DiskLib
|
||||
import NetLib
|
||||
|
||||
|
||||
|
||||
from GitLib import OpengnsysGitLibrary, NTFSImplementation, OgProgressPrinterWeb
|
||||
|
||||
|
||||
def commit_image(disk_num, partition_num, repo, image_name, msg):
|
||||
|
||||
ntfs_impl = NTFSImplementation.NTFS3G
|
||||
og_git = OpengnsysGitLibrary(ntfs_implementation = ntfs_impl)
|
||||
og_git.progress_callback = OgProgressPrinterWeb()
|
||||
|
||||
device = DiskLib.ogDiskToDev(disk_num, partition_num)
|
||||
og_git.initRepo(device, image_name)
|
||||
og_git.commit(device, msg)
|
||||
og_git.push()
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 6:
|
||||
sys.exit(SystemLib.ogRaiseError([], ogGlobals.OG_ERR_FORMAT, "Incorrect number of arguments. Usage: ModificarImagenGit.py disk_num partition_num image_name repo msg"))
|
||||
|
||||
# repo - repositorio, ip address. Opcional porque oglive lo recibe como parametro de kernel
|
||||
# tag - tag a crear automaticamente. Opcional, no necesitamos crear un tag siempre.
|
||||
|
||||
|
||||
disk_num, partition_num, image_name, repo, msg = sys.argv[1:6]
|
||||
|
||||
|
||||
opengnsys_log_dir = "/opt/opengnsys/log"
|
||||
ip_address = NetLib.ogGetIpAddress()
|
||||
logFilePath = f"{opengnsys_log_dir}/{ip_address}.log"
|
||||
|
||||
fileLog = logging.FileHandler(logFilePath)
|
||||
fileLog.setLevel(logging.DEBUG)
|
||||
|
||||
formatter = logging.Formatter('%(asctime)s - %(name)24s - [%(levelname)5s] - %(message)s')
|
||||
|
||||
fileLog.setFormatter(formatter)
|
||||
|
||||
logger = logging.getLogger(__package__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
logger.addHandler(fileLog)
|
||||
|
||||
logger.info("Starting ModificarImagenGit")
|
||||
|
||||
|
||||
retval = commit_image(disk_num, partition_num, repo, image_name, msg)
|
||||
|
||||
|
||||
|
||||
sys.exit(retval)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
|
@ -1,65 +1,32 @@
|
|||
#!/usr/bin/env python3
|
||||
import sys
|
||||
import resource
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
|
||||
sys.path.insert(0, "/opt/oglive/rootfs/opt/opengnsys/lib/python3/")
|
||||
sys.path.insert(0, "/opt/opengnsys/interfaceAdm/git/")
|
||||
sys.path.insert(0, "/opt/opengnsys/ogrepository/oggit/lib/")
|
||||
|
||||
import NetLib
|
||||
import ogGlobals
|
||||
import SystemLib
|
||||
import DiskLib
|
||||
|
||||
from GitLib import OpengnsysGitLibrary, NTFSImplementation, OgProgressPrinterWeb
|
||||
from gitlib import OpengnsysGitLibrary, NTFSImplementation
|
||||
|
||||
if __name__ == "__main__":
|
||||
soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
|
||||
try:
|
||||
# Usamos el mínimo entre 65536 y el límite hard disponible
|
||||
new_limit = min(65536, hard)
|
||||
resource.setrlimit(resource.RLIMIT_NOFILE, (new_limit, hard))
|
||||
print(f"RLIMIT_NOFILE establecido a: {resource.getrlimit(resource.RLIMIT_NOFILE)}")
|
||||
except ValueError as e:
|
||||
print(f"No se pudo aumentar el límite de archivos abiertos: {e}")
|
||||
|
||||
|
||||
if len(sys.argv) < 6:
|
||||
print("Usage: python RestaurarImagenGit.py <disk> <partition> <repo> <ip> <ref> <protocol>")
|
||||
if len(sys.argv) < 4:
|
||||
print("Usage: python RestaurarImagenGit.py <disk> <partition> <repo> <boot_device>")
|
||||
sys.exit(1)
|
||||
|
||||
disk = sys.argv[1]
|
||||
partition = sys.argv[2]
|
||||
repo = sys.argv[3]
|
||||
ipaddr = sys.argv[4]
|
||||
gitref = sys.argv[5]
|
||||
proto = sys.argv[6]
|
||||
|
||||
opengnsys_log_dir = "/opt/opengnsys/log"
|
||||
ip_address = NetLib.ogGetIpAddress()
|
||||
logFilePath = f"{opengnsys_log_dir}/{ip_address}.log"
|
||||
|
||||
fileLog = logging.FileHandler(logFilePath)
|
||||
fileLog.setLevel(logging.DEBUG)
|
||||
|
||||
formatter = logging.Formatter('%(asctime)s - %(name)24s - [%(levelname)5s] - %(message)s')
|
||||
|
||||
fileLog.setFormatter(formatter)
|
||||
|
||||
logger = logging.getLogger(__package__)
|
||||
logger.setLevel(logging.DEBUG)
|
||||
logger.addHandler(fileLog)
|
||||
|
||||
logger.info("Starting RestaurarImagenGit")
|
||||
|
||||
|
||||
|
||||
boot_device = sys.argv[4]
|
||||
|
||||
ntfs_impl = NTFSImplementation.NTFS3G
|
||||
og_git = OpengnsysGitLibrary(ntfs_implementation = ntfs_impl)
|
||||
og_git.progress_callback = OgProgressPrinterWeb()
|
||||
|
||||
device = DiskLib.ogDiskToDev(disk, partition)
|
||||
device = og_git._runBashFunction("ogDiskToDev", [str(disk), str(partition)])
|
||||
|
||||
og_git.cloneRepo(repo, device, device)
|
||||
|
||||
logger.info("RestaurarImagenGit Finished.")
|
||||
og_git.cloneRepo(repo, device, boot_device)
|
||||
|
||||
|
||||
|
|
|
@ -195,7 +195,7 @@ def ogBoot (disk, par, nvramperm=False, params=''):
|
|||
winboot = os.environ.get ('winboot', '')
|
||||
if 'kexec' == winboot:
|
||||
# Modo de arranque en caliente (con kexec).
|
||||
cp_cmd = f'cp {ogGlobals.OGLIB}/grub4dos/* {mntdir}' ## shutil sucks a bit for copying both files and dirs
|
||||
cp_cmd = f'cp {ogGlobals.OGLIB}/grub4dos/* {mntdir}'
|
||||
subprocess.run (cp_cmd, shell=True)
|
||||
disk0 = int(disk)-1
|
||||
par0 = int(par)-1
|
||||
|
|
|
@ -37,15 +37,16 @@ def ogCreateCache (ndsk=1, part=4, sizecache=0):
|
|||
NVME_PREFIX = 'p'
|
||||
|
||||
END = DiskLib.ogGetLastSector (ndsk)
|
||||
if not END:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, 'Failed to get last sector of disk')
|
||||
return None
|
||||
SIZE = 2 * sizecache
|
||||
# Inicio partición cache según el disco tenga sectores de 4k o menores
|
||||
IOSIZE = DiskLib.ogGetIoSize (ndsk)
|
||||
if not IOSIZE:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'Failed to get disk sector size')
|
||||
return None
|
||||
IOSIZE = 0
|
||||
fdisk_out = subprocess.run (['fdisk', '-l', DISK], capture_output=True, text=True).stdout
|
||||
for l in fdisk_out.splitlines():
|
||||
items = l.split()
|
||||
if len(items) < 4: continue
|
||||
if 'I/O' == items[0]:
|
||||
IOSIZE = int (items[3])
|
||||
break
|
||||
START = 0
|
||||
if 4096 == IOSIZE:
|
||||
END -= 8192
|
||||
|
@ -69,7 +70,7 @@ def ogCreateCache (ndsk=1, part=4, sizecache=0):
|
|||
MINSIZE = 25000
|
||||
MAXSIZE = END
|
||||
if SIZE < MINSIZE or SIZE > MAXSIZE or START < ENDPREVPART:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'size ({SIZE}) < minsize ({MINSIZE}) or size ({SIZE}) > maxsize ({MAXSIZE}) or start ({START}) < endprevpart ({ENDPREVPART})')
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_GENERIC, f'size ({SIZE}) < minsize ({MINSIZE}) or size > maxsize ({MAXSIZE}) or start ({START}) < endprevpart ({ENDPREVPART})')
|
||||
return None
|
||||
|
||||
# Desmontar todos los sistemas de archivos del disco.
|
||||
|
@ -89,32 +90,27 @@ def ogCreateCache (ndsk=1, part=4, sizecache=0):
|
|||
subprocess.run (['gdisk', DISK], input='2\nw\nY\n', capture_output=True, text=True)
|
||||
# Si existe la cache se borra previamente
|
||||
if ogFindCache(): ogDeleteCache()
|
||||
|
||||
ID = DiskLib.ogTypeToId ('LINUX', 'GPT_GUID')
|
||||
sfdisk_line = f'{DISK}{NVME_PREFIX}{part} : start= {START}, size= {SIZE}, type={ID}, name=CACHE'
|
||||
# Capturamos el codigo de particion GPT para cache
|
||||
# PATCH - Cuando es GPT, la particion con codigo CACHE (CA00) no existe y no puede crearse, se cambia por LINUX (8300)
|
||||
ID = DiskLib.ogTypeToId ('LINUX', 'GPT')
|
||||
subprocess.run (['sgdisk', DISK, f'-n{part}:{START}:{END}', f'-c{part}:CACHE', f'-t{part}:{ID}'])
|
||||
elif 'MSDOS' == get_ptt:
|
||||
# Si la tabla de particiones no es valida, volver a generarla.
|
||||
if subprocess.run (['parted', '-s', DISK, 'print'], capture_output=True).returncode: ## if True, then parted failed
|
||||
subprocess.run (['fdisk', DISK], input='w\n', text=True, capture_output=True)
|
||||
|
||||
if subprocess.run (['parted', '-s', DISK, 'print']).returncode: ## if True, then parted failed
|
||||
subprocess.run (['fdisk', DISK], input='w\n', text=True)
|
||||
# Definir particiones y notificar al kernel.
|
||||
ID = DiskLib.ogTypeToId ('CACHE', 'MSDOS')
|
||||
sfdisk_line = f'{DISK}{NVME_PREFIX}{part} : start= {START}, size= {SIZE}, Id={ID}'
|
||||
else:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, 'No hay tabla de particiones en el disco')
|
||||
return False
|
||||
|
||||
# Salvamos la configuración de las particiones e incluimos la cache.
|
||||
tmp = subprocess.run (['sfdisk', '--dump', DISK], capture_output=True, text=True).stdout.splitlines()
|
||||
tmp = [ x for x in tmp if f'{DISK}{part}' not in x ] ## grep -v la_de_cache
|
||||
tmp.append (sfdisk_line)
|
||||
# Ordenamos las líneas de los dispositivos
|
||||
UNIT = [ x for x in tmp if 'unit' in x ][0]
|
||||
tmp = sorted ([ x for x in tmp if re.match ('^/dev', x) ])
|
||||
tmp = [UNIT, ''] + tmp
|
||||
# Guardamos nueva configuración en el disco.
|
||||
i = '\n'.join(tmp)
|
||||
subprocess.run (['sfdisk', '--no-reread', DISK], input=i, text=True)
|
||||
|
||||
# Salvamos la configuración de las particiones e incluimos la cache.
|
||||
tmp = subprocess.run (['sfdisk', '--dump', DISK], capture_output=True, text=True).stdout.splitlines()
|
||||
tmp = [ x for x in tmp if f'{DISK}{part}' not in x ]
|
||||
tmp.append (f'{DISK}{NVME_PREFIX}{part} : start= {START}, size= {SIZE}, Id={ID}')
|
||||
# Ordenamos las líneas de los dispositivos
|
||||
UNIT = [ x for x in tmp if 'unit' in x ][0]
|
||||
tmp = sorted ([ x for x in tmp if re.match ('^/dev', x) ])
|
||||
tmp = [UNIT, ''] + tmp
|
||||
# Guardamos nueva configuración en el disco.
|
||||
i = '\n'.join(tmp)
|
||||
subprocess.run (['sfdisk', '--no-reread', DISK], input=i, text=True)
|
||||
# Actualiza la tabla de particiones en el kernel.
|
||||
DiskLib.ogUpdatePartitionTable()
|
||||
return True
|
||||
|
@ -143,15 +139,15 @@ def ogDeleteCache():
|
|||
ptt = DiskLib.ogGetPartitionTableType (ndisk)
|
||||
if 'GPT' == ptt:
|
||||
# Si la tabla de particiones no es valida, volver a generarla.
|
||||
if subprocess.run (['sgdisk', '-p', disk], capture_output=True).returncode: ## if True, then sgdisk failed
|
||||
subprocess.run (['gdisk', disk], input='2\nw\nY\n', text=True, capture_output=True)
|
||||
if subprocess.run (['sgdisk', '-p', disk]).returncode: ## if True, then sgdisk failed
|
||||
subprocess.run (['gdisk', disk], input='2\nw\nY\n', text=True)
|
||||
subprocess.run (['sgdisk', disk, f'-d{npart}'])
|
||||
elif 'MSDOS' == ptt:
|
||||
# Si la tabla de particiones no es valida, volver a generarla.
|
||||
if subprocess.run (['parted', '-s', disk, 'print'], capture_output=True).returncode: ## if True, then parted failed
|
||||
subprocess.run (['fdisk', disk], input='w', text=True, capture_output=True)
|
||||
if subprocess.run (['parted', '-s', disk, 'print']).returncode: ## if True, then parted failed
|
||||
subprocess.run (['fdisk', disk], input='w', text=True)
|
||||
# Eliminar la partición de caché.
|
||||
subprocess.run (['fdisk', disk], input=f'd\n{npart}\nw', text=True, capture_output=True)
|
||||
subprocess.run (['fdisk', disk], input=f'd\n{npart}\nw', text=True)
|
||||
# Borrar etiqueta de la caché.
|
||||
if os.path.exists ('/dev/disk/by-label/CACHE'):
|
||||
os.unlink ('/dev/disk/by-label/CACHE')
|
||||
|
@ -362,46 +358,3 @@ def ogUnmountCache():
|
|||
def initCache (*args):
|
||||
p = subprocess.run ([f'{ogGlobals.OGSCRIPTS}/initCache.py'] + list(args))
|
||||
return not p.returncode ## negate shell return code
|
||||
|
||||
|
||||
#/**
|
||||
# ogCheckNewCacheSize
|
||||
#@brief Comprueba si un cache de X tamaño cabe en el hueco que dejan las demás particiones
|
||||
#@param Tamaño de la nueva hipotética cache
|
||||
#@return Boolean, True si la nueva cache cabría, False si no
|
||||
#*/ ##
|
||||
def ogCheckNewCacheSize (disk, kB):
|
||||
DISK = DiskLib.ogDiskToDev (disk)
|
||||
if not DISK: return None
|
||||
|
||||
IOSIZE = DiskLib.ogGetIoSize (disk)
|
||||
if not IOSIZE:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'Failed to get disk sector size')
|
||||
return None
|
||||
last_sector = DiskLib.ogGetLastSector (disk)
|
||||
|
||||
end_of_last_partition = 0
|
||||
cachepart = ogFindCache()
|
||||
if cachepart:
|
||||
cache_disk, cache_part = cachepart.split()
|
||||
cache_dev = DiskLib.ogDiskToDev (cache_disk, cache_part)
|
||||
else:
|
||||
cache_dev = None
|
||||
fdisk_l_out = subprocess.run (['fdisk', '-l', DISK], capture_output=True, text=True).stdout
|
||||
for l in fdisk_l_out.splitlines():
|
||||
if not re.match ('^/dev', l): ## no empieza por /dev, nos la saltamos
|
||||
continue
|
||||
if cache_dev and re.match (f'^{cache_dev}', l): ## es la de cache, nos la saltamos
|
||||
continue
|
||||
last_sector_of_partition = int (l.split()[2])
|
||||
if last_sector_of_partition > end_of_last_partition:
|
||||
end_of_last_partition = last_sector_of_partition
|
||||
|
||||
if 512 == IOSIZE:
|
||||
cache_sectors = kB*2
|
||||
else: ## 4096
|
||||
cache_sectors = (kB+3)//4 ## sumamos 3 para que la división entera "redondee al alza"
|
||||
if end_of_last_partition + cache_sectors > last_sector:
|
||||
SystemLib.ogEcho (['session', 'log'], None, f'end_of_last_partition ({end_of_last_partition}) + cache_sectors ({cache_sectors}) > last_sector ({last_sector}), check failed')
|
||||
return False
|
||||
return True
|
||||
|
|
|
@ -38,32 +38,6 @@ def parted(*args):
|
|||
return "Error: 'parted' command not found"
|
||||
|
||||
|
||||
#/**
|
||||
# ogGetIoSize int_ndisk
|
||||
#@brief Devuelve el tamaño de sector de un disco
|
||||
#@param int_ndisk nº de orden del disco
|
||||
#@return Tamaño de sector
|
||||
#*/ ##
|
||||
def ogGetIoSize (disk):
|
||||
DISK = ogDiskToDev (disk)
|
||||
if not DISK: return None
|
||||
|
||||
IOSIZE = None
|
||||
fdisk_out = subprocess.run (['fdisk', '-l', DISK], capture_output=True, text=True).stdout
|
||||
for l in fdisk_out.splitlines():
|
||||
if 'I/O' not in l: continue
|
||||
items = l.split()
|
||||
if len(items) < 4: continue
|
||||
IOSIZE = items[3]
|
||||
break
|
||||
|
||||
if IOSIZE is None:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'Could not extract disk sector size from fdisk output')
|
||||
return None
|
||||
|
||||
return int (IOSIZE)
|
||||
|
||||
|
||||
#/**
|
||||
# ogCreatePartitions int_ndisk str_parttype:int_partsize ...
|
||||
#@brief Define el conjunto de particiones de un disco.
|
||||
|
@ -87,11 +61,12 @@ def ogCreatePartitions (disk, parts):
|
|||
|
||||
PTTYPE = ogGetPartitionTableType (disk)
|
||||
if not PTTYPE: PTTYPE = 'MSDOS' # Por defecto para discos vacíos.
|
||||
if PTTYPE not in ['MSDOS', 'GPT']:
|
||||
|
||||
if 'GPT' == PTTYPE:
|
||||
return ogCreateGptPartitions (disk, parts)
|
||||
elif 'MSDOS' != PTTYPE:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, PTTYPE)
|
||||
return None
|
||||
if 'MSDOS' == PTTYPE: CACHE_ID = ogTypeToId ('CACHE', 'MSDOS')
|
||||
else: CACHE_ID = ogTypeToId ('CACHE', 'GPT_GUID')
|
||||
|
||||
# Se calcula el ultimo sector del disco (total de sectores usables)
|
||||
SECTORS = ogGetLastSector (disk)
|
||||
|
@ -103,21 +78,24 @@ def ogCreatePartitions (disk, parts):
|
|||
cache_disk, cache_part = CACHEPART.split()
|
||||
if int (ND) == int (cache_disk):
|
||||
CACHESIZE = int (CacheLib.ogGetCacheSize()) * 2
|
||||
|
||||
# Sector de inicio (la partición 1 empieza en el sector 63).
|
||||
IOSIZE = ogGetIoSize (ND)
|
||||
if not IOSIZE:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'Failed to get disk sector size')
|
||||
return None
|
||||
IODISCO = ogDiskToDev (disk)
|
||||
IOSIZE = 0
|
||||
fdisk_out = subprocess.run (['fdisk', '-l', IODISCO], capture_output=True, text=True).stdout
|
||||
for l in fdisk_out.splitlines():
|
||||
if 'I/O' not in l: continue
|
||||
items = l.split()
|
||||
if len(items) < 4: continue
|
||||
IOSIZE = items[3]
|
||||
break
|
||||
|
||||
if 4096 == IOSIZE:
|
||||
if '4096' == IOSIZE:
|
||||
START = 4096
|
||||
SECTORS -= 8192
|
||||
if CACHESIZE:
|
||||
SECTORS = SECTORS - CACHESIZE + 2048 - (SECTORS - CACHESIZE) % 2048 - 1
|
||||
else: ## 512
|
||||
if 'MSDOS' == PTTYPE: START = 63
|
||||
else: START = 2048
|
||||
else:
|
||||
START = 63
|
||||
if CACHESIZE:
|
||||
SECTORS -= CACHESIZE
|
||||
|
||||
|
@ -125,108 +103,71 @@ def ogCreatePartitions (disk, parts):
|
|||
|
||||
sfdisk_input = 'unit: sectors\n\n'
|
||||
NVME_PREFIX = 'p' if 'nvme' in DISK else ''
|
||||
EXTSTART = EXTSIZE = 0
|
||||
for p in parts:
|
||||
# Conservar los datos de la partición de caché.
|
||||
if f'{ND} {PART}' == CACHEPART and CACHESIZE:
|
||||
sfdisk_input += f'{DISK}{NVME_PREFIX}{PART} : start={SECTORS+1}, size={CACHESIZE}, Id=ca\n'
|
||||
PART += 1
|
||||
continue
|
||||
|
||||
# Leer formato de cada parámetro - Tipo:Tamaño
|
||||
TYPE, SIZE = p.split (':')
|
||||
if TYPE is None or 'None' == TYPE: TYPE='EMPTY'
|
||||
|
||||
# Obtener identificador de tipo de partición válido.
|
||||
if 'GPT' == PTTYPE:
|
||||
ID = ogTypeToId (TYPE, 'GPT_GUID')
|
||||
else:
|
||||
ID = ogTypeToId (TYPE, PTTYPE)
|
||||
|
||||
# Conservar los datos de la partición de caché.
|
||||
if f'{ND} {PART}' == CACHEPART and CACHESIZE:
|
||||
sfdisk_input += f'{DISK}{NVME_PREFIX}{PART} : start={SECTORS+1}, size={CACHESIZE}, type={CACHE_ID}\n'
|
||||
PART += 1
|
||||
|
||||
try:
|
||||
SIZE = int (SIZE)
|
||||
except ValueError:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, SIZE)
|
||||
return None
|
||||
|
||||
# Obtener identificador de tipo de partición válido.
|
||||
ID = ogTypeToId (TYPE, 'MSDOS')
|
||||
if 'CACHE' == TYPE or not ID:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, TYPE)
|
||||
return None
|
||||
|
||||
# Comprobar tamaño numérico y convertir en sectores
|
||||
ORIG_SIZE = SIZE ## para reportar en un error
|
||||
if 512 == IOSIZE: SIZE *= 2
|
||||
else: SIZE = (SIZE+3)//4 ## sumamos 3 para que la división entera "redondee al alza"
|
||||
|
||||
# Comprobar tamaño numérico y convertir en sectores de 512 B.
|
||||
SIZE *= 2
|
||||
# Comprobar si la partición es extendida.
|
||||
if '5' == ID:
|
||||
if 'GPT' == PTTYPE:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, 'EXTENDED')
|
||||
EXTSTART = EXTSIZE = 0
|
||||
if 5 == ID:
|
||||
if PART > 4:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, '')
|
||||
return None
|
||||
|
||||
## la extendida debe ser:
|
||||
## - si no estamos creando cache: /dev/sda4
|
||||
## - si sí estamos creando cache: /dev/sda3
|
||||
## de lo contrario, crea eg. esto:
|
||||
## Device Boot Start End Sectors Size Id Type
|
||||
## /dev/sda1 63 222444728 222444666 106,1G 82 Linux swap / Solaris
|
||||
## /dev/sda2 222444729 244889394 22444666 10,7G 5 Extended <---------
|
||||
## /dev/sda3 244889395 251334060 6444666 3,1G 83 Linux <---------
|
||||
## /dev/sda4 314103633 314572766 469134 229,1M ca unknown
|
||||
## /dev/sda5 222446777 224891442 2444666 1,2G 83 Linux
|
||||
## /dev/sda6 224891443 229558330 4666888 2,2G 83 Linux
|
||||
## la sda2 es extendida, y las lógicas deberían ser sda5, sda6, sda7
|
||||
## pero esto mete una sda3 como lógica, y luego va el cache que es primaria... WTF
|
||||
error_in_extended = False
|
||||
if CACHEPART and PART != 3: error_in_extended = True
|
||||
if not CACHEPART and PART != 4: error_in_extended = True
|
||||
if PART > 4: error_in_extended = True
|
||||
if error_in_extended:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'No se puede definir la partición extendida en la partición "{PART}"')
|
||||
return None
|
||||
|
||||
# El inicio de la primera partición logica es el de la extendida más 4x512
|
||||
EXTSTART = START+2048
|
||||
EXTSIZE = SIZE-2048
|
||||
# Incluir particiones lógicas dentro de la partición extendida.
|
||||
if 5 == PART:
|
||||
if 'GPT' == PTTYPE:
|
||||
pass ## sin problema, la partición 5 es simplemente una más
|
||||
else:
|
||||
if not EXTSTART:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, 'la partición 5 es lógica pero no hay ninguna EXTENDED definida antes')
|
||||
return None
|
||||
START = EXTSTART
|
||||
SECTORS = EXTSTART+EXTSIZE
|
||||
if not EXTSTART:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, '')
|
||||
return None
|
||||
START = EXTSTART
|
||||
SECTORS = EXTSTART+EXTSIZE
|
||||
|
||||
# Generar datos para la partición.
|
||||
# En el caso de que la partición sea EMPTY no se crea nada
|
||||
if 'EMPTY' != TYPE:
|
||||
sfdisk_input += f'{DISK}{NVME_PREFIX}{PART} : start={START}, size={SIZE}, type={ID}\n'
|
||||
sfdisk_input += f'{DISK}{NVME_PREFIX}{PART} : start={START}, size={SIZE}, Id={ID}\n'
|
||||
|
||||
START += SIZE
|
||||
|
||||
if 'MSDOS' == PTTYPE and 4096 == IOSIZE and PART > 4:
|
||||
START += 2048
|
||||
|
||||
# Error si se supera el nº total de sectores.
|
||||
if '4096' == IOSIZE and PART > 4:
|
||||
START += 2048
|
||||
if START > SECTORS:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'partición "{TYPE}:{ORIG_SIZE}" no cabe')
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'{START//2} > {SECTORS//2}')
|
||||
return None
|
||||
PART += 1
|
||||
|
||||
# Si no se indican las 4 particiones primarias, definirlas como vacías, conservando la partición de caché.
|
||||
while PART <= 4:
|
||||
if f'{ND} {PART}' == CACHEPART and CACHESIZE:
|
||||
sfdisk_input += f'{DISK}{NVME_PREFIX}{PART} : start={SECTORS+1}, size={CACHESIZE}, type={CACHE_ID}\n'
|
||||
sfdisk_input += f'{DISK}{NVME_PREFIX}{PART} : start={SECTORS+1}, size={CACHESIZE}, Id=ca\n'
|
||||
else:
|
||||
sfdisk_input += f'{DISK}{NVME_PREFIX}{PART} : start=0, size=0, type=0\n'
|
||||
sfdisk_input += f'{DISK}{NVME_PREFIX}{PART} : start=0, size=0, Id=0\n'
|
||||
PART += 1
|
||||
|
||||
# Si se define partición extendida sin lógicas, crear particion 5 vacía.
|
||||
if 5 == PART and EXTSTART:
|
||||
ID = ogTypeToId ('WINDOWS', PTTYPE)
|
||||
sfdisk_input += f'{DISK}5 : start={EXTSTART}, SIZE={EXTSIZE}, type={ID}\n'
|
||||
sfdisk_input += f'{DISK}5 : start={EXTSTART}, SIZE={EXTSIZE}, Id=0\n'
|
||||
|
||||
# Desmontar los sistemas de archivos del disco antes de realizar las operaciones.
|
||||
FileSystemLib.ogUnmountAll (ND)
|
||||
|
@ -242,6 +183,113 @@ def ogCreatePartitions (disk, parts):
|
|||
return not p.returncode
|
||||
|
||||
|
||||
#/**
|
||||
# ogCreateGptPartitions int_ndisk str_parttype:int_partsize ...
|
||||
#@brief Define el conjunto de particiones de un disco GPT
|
||||
#@param int_ndisk nº de orden del disco
|
||||
#@param str_parttype mnemónico del tipo de partición
|
||||
#@param int_partsize tamaño de la partición (en KB)
|
||||
#@return (nada, por determinar)
|
||||
#@exception OG_ERR_FORMAT formato incorrecto.
|
||||
#@exception OG_ERR_NOTFOUND disco o partición no detectado (no es un dispositivo).
|
||||
#@exception OG_ERR_PARTITION error en partición o en tabla de particiones.
|
||||
#@attention El nº de partición se indica por el orden de los párametros \c parttype:partsize
|
||||
#@attention Pueden definirse particiones vacías de tipo \c EMPTY
|
||||
#@attention No puede definirse partición de caché y no se modifica si existe.
|
||||
#@note Requisitos: sfdisk, parted, partprobe, awk
|
||||
#@todo Definir atributos (arranque, oculta) y tamaños en MB, GB, etc.
|
||||
#*/ ##
|
||||
def ogCreateGptPartitions (disk, parts):
|
||||
ND = disk
|
||||
DISK = ogDiskToDev (ND)
|
||||
if not DISK: return None
|
||||
|
||||
# Se calcula el ultimo sector del disco (total de sectores usables)
|
||||
SECTORS = ogGetLastSector (disk)
|
||||
|
||||
# Se recalcula el nº de sectores del disco si existe partición de caché.
|
||||
CACHESIZE = 0
|
||||
CACHEPART = CacheLib.ogFindCache()
|
||||
if CACHEPART:
|
||||
cache_disk, cache_part = CACHEPART.split()
|
||||
if ND == cache_disk:
|
||||
CACHESIZE = int (CacheLib.ogGetCacheSize()) * 2
|
||||
if CACHESIZE:
|
||||
SECTORS -= CACHESIZE
|
||||
|
||||
# Si el disco es GPT empieza en el sector 2048 por defecto, pero podria cambiarse
|
||||
ALIGN = int (subprocess.run (['sgdisk', '-D', DISK], capture_output=True, text=True).stdout)
|
||||
START = ALIGN
|
||||
PART = 1
|
||||
print (f'START ({START}) SECTORS ({SECTORS}) PART ({PART})')
|
||||
|
||||
# Leer parámetros con definición de particionado.
|
||||
DELOPTIONS = []
|
||||
OPTIONS = []
|
||||
for p in parts:
|
||||
# Conservar los datos de la partición de caché.
|
||||
if f'{ND} {PART}' == CACHEPART and CACHESIZE:
|
||||
PART += 1
|
||||
|
||||
# Leer formato de cada parámetro - Tipo:Tamaño
|
||||
TYPE, SIZE = p.split (':')
|
||||
try:
|
||||
SIZE = int (SIZE)
|
||||
except ValueError:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, SIZE)
|
||||
return None
|
||||
|
||||
# Error si la partición es extendida (no válida en discos GPT).
|
||||
if 'EXTENDED' == TYPE:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, 'EXTENDED')
|
||||
return None
|
||||
|
||||
# Comprobar si existe la particion actual, capturamos su tamaño para ver si cambio o no
|
||||
PARTSIZE = ogGetPartitionSize (ND, PART)
|
||||
# En sgdisk no se pueden redimensionar las particiones, es necesario borrarlas y volver a crealas
|
||||
if PARTSIZE:
|
||||
DELOPTIONS.append (f'-d{PART}')
|
||||
|
||||
# Creamos la particion
|
||||
# Obtener identificador de tipo de partición válido.
|
||||
ID = ogTypeToId (TYPE, 'GPT')
|
||||
if 'CACHE' == TYPE or not ID:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, TYPE)
|
||||
return None
|
||||
# Comprobar tamaño numérico y convertir en sectores de 512 B.
|
||||
SIZE *= 2
|
||||
# SIZE debe ser múltiplo de ALIGN, si no gdisk lo mueve automáticamente.
|
||||
SIZE = (SIZE // ALIGN) * ALIGN
|
||||
|
||||
# Generar datos para la partición.
|
||||
# En el caso de que la partición sea EMPTY no se crea nada
|
||||
if 'EMPTY' != TYPE:
|
||||
OPTIONS += [f'-n{PART}:{START}:+{SIZE}', f'-t{PART}:{ID}']
|
||||
|
||||
START += SIZE
|
||||
|
||||
# Error si se supera el nº total de sectores.
|
||||
if START > SECTORS:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'{START//2} > {SECTORS//2}')
|
||||
return None
|
||||
|
||||
PART += 1
|
||||
|
||||
# Desmontar los sistemas de archivos del disco antes de realizar las operaciones.
|
||||
FileSystemLib.ogUnmountAll (ND)
|
||||
if CACHESIZE: CacheLib.ogUnmountCache()
|
||||
|
||||
# Si la tabla de particiones no es valida, volver a generarla.
|
||||
ogCreatePartitionTable (ND, 'GPT')
|
||||
|
||||
# Definir particiones y notificar al kernel.
|
||||
p = subprocess.run (['sgdisk'] + DELOPTIONS + OPTIONS + [DISK], capture_output=True, text=True)
|
||||
print (f'sgdisk rc ({p.returncode}) stdout ({p.stdout}) stderr ({p.stderr})')
|
||||
subprocess.run (['partprobe', DISK])
|
||||
if CACHESIZE: CacheLib.ogMountCache()
|
||||
return not p.returncode
|
||||
|
||||
|
||||
#/**
|
||||
# ogCreatePartitionTable int_ndisk [str_tabletype]
|
||||
#@brief Genera una tabla de particiones en caso de que no sea valida, si es valida no hace nada.
|
||||
|
@ -383,7 +431,7 @@ def ogDevToDisk(arg_dev):
|
|||
|
||||
def _getAllDisks():
|
||||
ret = []
|
||||
all_disks = subprocess.run("lsblk -n -e 1,2 -x NAME 2>/dev/null || lsblk -n -e 1,2", shell=True, capture_output=True, text=True).stdout.splitlines()
|
||||
all_disks = subprocess.run("lsblk -n -e 1,2 -x MAJ:MIN 2>/dev/null || lsblk -n -e 1,2", shell=True, capture_output=True, text=True).stdout.splitlines()
|
||||
for line in all_disks:
|
||||
parts = line.split()
|
||||
if parts[5] == "disk":
|
||||
|
@ -810,7 +858,7 @@ def ogGetPartitionSize (disk, par):
|
|||
#@return Devuelve el numero paritiones del disco duro indicado
|
||||
#@warning Salidas de errores no determinada
|
||||
#@attention Requisitos: parted
|
||||
#@note Notas sin especificar
|
||||
#@note Notas sin especificar
|
||||
#*/ ##
|
||||
def ogGetPartitionsNumber (disk):
|
||||
DISK = ogDiskToDev (disk)
|
||||
|
@ -1229,23 +1277,6 @@ def ogSetPartitionType (disk, par, t):
|
|||
#ogTypeToId ('LINUX', 'MSDOS') => "83"
|
||||
def ogTypeToId (type, pttype='MSDOS'):
|
||||
data = {
|
||||
'GPT_GUID': {
|
||||
## https://en.wikipedia.org/wiki/GUID_Partition_Table?useskin=vector
|
||||
'EMPTY': '0',
|
||||
'WINDOWS': 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7',
|
||||
'NTFS': 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7',
|
||||
'FAT32': 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7',
|
||||
'FAT16': 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7',
|
||||
'FAT12': 'EBD0A0A2-B9E5-4433-87C0-68B6B72699C7',
|
||||
'WIN-RESERV': 'E3C9E316-0B5C-4DB8-817D-F92DF00215AE',
|
||||
'LINUX-SWAP': '0657FD6D-A4AB-43C4-84E5-0933C84B4F4F',
|
||||
'LINUX': '0FC63DAF-8483-4772-8E79-3D69D8477DE4',
|
||||
'EXT2': '0FC63DAF-8483-4772-8E79-3D69D8477DE4',
|
||||
'EXT3': '0FC63DAF-8483-4772-8E79-3D69D8477DE4',
|
||||
'EXT4': '0FC63DAF-8483-4772-8E79-3D69D8477DE4',
|
||||
'CACHE': '0FC63DAF-8483-4772-8E79-3D69D8477DE4',
|
||||
'EFI': 'C12A7328-F81F-11D2-BA4B-00A0C93EC93B',
|
||||
},
|
||||
'GPT': {
|
||||
'EMPTY': '0',
|
||||
'WINDOWS': '0700',
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,345 +0,0 @@
|
|||
#!/usr/bin/env python3
|
||||
import hivex
|
||||
import argparse
|
||||
import struct
|
||||
|
||||
from hivex import Hivex
|
||||
from hivex.hive_types import *
|
||||
|
||||
|
||||
# Docs:
|
||||
#
|
||||
# https://www.geoffchappell.com/notes/windows/boot/bcd/objects.htm
|
||||
# https://learn.microsoft.com/en-us/previous-versions/windows/desktop/bcd/bcdbootmgrelementtypes
|
||||
|
||||
#print(f"Root: {root}")
|
||||
|
||||
|
||||
BCD_Enumerations = {
|
||||
"BcdLibraryDevice_ApplicationDevice" : 0x11000001,
|
||||
"BcdLibraryString_ApplicationPath" : 0x12000002,
|
||||
"BcdLibraryString_Description" : 0x12000004,
|
||||
"BcdLibraryString_PreferredLocale" : 0x12000005,
|
||||
"BcdLibraryObjectList_InheritedObjects" : 0x14000006,
|
||||
"BcdLibraryInteger_TruncatePhysicalMemory" : 0x15000007,
|
||||
"BcdLibraryObjectList_RecoverySequence" : 0x14000008,
|
||||
"BcdLibraryBoolean_AutoRecoveryEnabled" : 0x16000009,
|
||||
"BcdLibraryIntegerList_BadMemoryList" : 0x1700000a,
|
||||
"BcdLibraryBoolean_AllowBadMemoryAccess" : 0x1600000b,
|
||||
"BcdLibraryInteger_FirstMegabytePolicy" : 0x1500000c,
|
||||
"BcdLibraryInteger_RelocatePhysicalMemory" : 0x1500000D,
|
||||
"BcdLibraryInteger_AvoidLowPhysicalMemory" : 0x1500000E,
|
||||
"BcdLibraryBoolean_DebuggerEnabled" : 0x16000010,
|
||||
"BcdLibraryInteger_DebuggerType" : 0x15000011,
|
||||
"BcdLibraryInteger_SerialDebuggerPortAddress" : 0x15000012,
|
||||
"BcdLibraryInteger_SerialDebuggerPort" : 0x15000013,
|
||||
"BcdLibraryInteger_SerialDebuggerBaudRate" : 0x15000014,
|
||||
"BcdLibraryInteger_1394DebuggerChannel" : 0x15000015,
|
||||
"BcdLibraryString_UsbDebuggerTargetName" : 0x12000016,
|
||||
"BcdLibraryBoolean_DebuggerIgnoreUsermodeExceptions" : 0x16000017,
|
||||
"BcdLibraryInteger_DebuggerStartPolicy" : 0x15000018,
|
||||
"BcdLibraryString_DebuggerBusParameters" : 0x12000019,
|
||||
"BcdLibraryInteger_DebuggerNetHostIP" : 0x1500001A,
|
||||
"BcdLibraryInteger_DebuggerNetPort" : 0x1500001B,
|
||||
"BcdLibraryBoolean_DebuggerNetDhcp" : 0x1600001C,
|
||||
"BcdLibraryString_DebuggerNetKey" : 0x1200001D,
|
||||
"BcdLibraryBoolean_EmsEnabled" : 0x16000020,
|
||||
"BcdLibraryInteger_EmsPort" : 0x15000022,
|
||||
"BcdLibraryInteger_EmsBaudRate" : 0x15000023,
|
||||
"BcdLibraryString_LoadOptionsString" : 0x12000030,
|
||||
"BcdLibraryBoolean_DisplayAdvancedOptions" : 0x16000040,
|
||||
"BcdLibraryBoolean_DisplayOptionsEdit" : 0x16000041,
|
||||
"BcdLibraryDevice_BsdLogDevice" : 0x11000043,
|
||||
"BcdLibraryString_BsdLogPath" : 0x12000044,
|
||||
"BcdLibraryBoolean_GraphicsModeDisabled" : 0x16000046,
|
||||
"BcdLibraryInteger_ConfigAccessPolicy" : 0x15000047,
|
||||
"BcdLibraryBoolean_DisableIntegrityChecks" : 0x16000048,
|
||||
"BcdLibraryBoolean_AllowPrereleaseSignatures" : 0x16000049,
|
||||
"BcdLibraryString_FontPath" : 0x1200004A,
|
||||
"BcdLibraryInteger_SiPolicy" : 0x1500004B,
|
||||
"BcdLibraryInteger_FveBandId" : 0x1500004C,
|
||||
"BcdLibraryBoolean_ConsoleExtendedInput" : 0x16000050,
|
||||
"BcdLibraryInteger_GraphicsResolution" : 0x15000052,
|
||||
"BcdLibraryBoolean_RestartOnFailure" : 0x16000053,
|
||||
"BcdLibraryBoolean_GraphicsForceHighestMode" : 0x16000054,
|
||||
"BcdLibraryBoolean_IsolatedExecutionContext" : 0x16000060,
|
||||
"BcdLibraryBoolean_BootUxDisable" : 0x1600006C,
|
||||
"BcdLibraryBoolean_BootShutdownDisabled" : 0x16000074,
|
||||
"BcdLibraryIntegerList_AllowedInMemorySettings" : 0x17000077,
|
||||
"BcdLibraryBoolean_ForceFipsCrypto" : 0x16000079,
|
||||
|
||||
|
||||
"BcdBootMgrObjectList_DisplayOrder" : 0x24000001,
|
||||
"BcdBootMgrObjectList_BootSequence" : 0x24000002,
|
||||
"BcdBootMgrObject_DefaultObject" : 0x23000003,
|
||||
"BcdBootMgrInteger_Timeout" : 0x25000004,
|
||||
"BcdBootMgrBoolean_AttemptResume" : 0x26000005,
|
||||
"BcdBootMgrObject_ResumeObject" : 0x23000006,
|
||||
"BcdBootMgrObjectList_ToolsDisplayOrder" : 0x24000010,
|
||||
"BcdBootMgrBoolean_DisplayBootMenu" : 0x26000020,
|
||||
"BcdBootMgrBoolean_NoErrorDisplay" : 0x26000021,
|
||||
"BcdBootMgrDevice_BcdDevice" : 0x21000022,
|
||||
"BcdBootMgrString_BcdFilePath" : 0x22000023,
|
||||
"BcdBootMgrBoolean_ProcessCustomActionsFirst" : 0x26000028,
|
||||
"BcdBootMgrIntegerList_CustomActionsList" : 0x27000030,
|
||||
"BcdBootMgrBoolean_PersistBootSequence" : 0x26000031,
|
||||
|
||||
"BcdDeviceInteger_RamdiskImageOffset" : 0x35000001,
|
||||
"BcdDeviceInteger_TftpClientPort" : 0x35000002,
|
||||
"BcdDeviceInteger_SdiDevice" : 0x31000003,
|
||||
"BcdDeviceInteger_SdiPath" : 0x32000004,
|
||||
"BcdDeviceInteger_RamdiskImageLength" : 0x35000005,
|
||||
"BcdDeviceBoolean_RamdiskExportAsCd" : 0x36000006,
|
||||
"BcdDeviceInteger_RamdiskTftpBlockSize" : 0x36000007,
|
||||
"BcdDeviceInteger_RamdiskTftpWindowSize" : 0x36000008,
|
||||
"BcdDeviceBoolean_RamdiskMulticastEnabled" : 0x36000009,
|
||||
"BcdDeviceBoolean_RamdiskMulticastTftpFallback" : 0x3600000A,
|
||||
"BcdDeviceBoolean_RamdiskTftpVarWindow" : 0x3600000B,
|
||||
|
||||
"BcdMemDiagInteger_PassCount" : 0x25000001,
|
||||
"BcdMemDiagInteger_FailureCount" : 0x25000003,
|
||||
|
||||
"Reserved1" : 0x21000001,
|
||||
"Reserved2" : 0x22000002,
|
||||
"BcdResumeBoolean_UseCustomSettings" : 0x26000003,
|
||||
"BcdResumeDevice_AssociatedOsDevice" : 0x21000005,
|
||||
"BcdResumeBoolean_DebugOptionEnabled" : 0x26000006,
|
||||
"BcdResumeInteger_BootMenuPolicy" : 0x25000008,
|
||||
|
||||
"BcdOSLoaderDevice_OSDevice" : 0x21000001,
|
||||
"BcdOSLoaderString_SystemRoot" : 0x22000002,
|
||||
"BcdOSLoaderObject_AssociatedResumeObject" : 0x23000003,
|
||||
"BcdOSLoaderBoolean_DetectKernelAndHal" : 0x26000010,
|
||||
"BcdOSLoaderString_KernelPath" : 0x22000011,
|
||||
"BcdOSLoaderString_HalPath" : 0x22000012,
|
||||
"BcdOSLoaderString_DbgTransportPath" : 0x22000013,
|
||||
"BcdOSLoaderInteger_NxPolicy" : 0x25000020,
|
||||
"BcdOSLoaderInteger_PAEPolicy" : 0x25000021,
|
||||
"BcdOSLoaderBoolean_WinPEMode" : 0x26000022,
|
||||
"BcdOSLoaderBoolean_DisableCrashAutoReboot" : 0x26000024,
|
||||
"BcdOSLoaderBoolean_UseLastGoodSettings" : 0x26000025,
|
||||
"BcdOSLoaderBoolean_AllowPrereleaseSignatures" : 0x26000027,
|
||||
"BcdOSLoaderBoolean_NoLowMemory" : 0x26000030,
|
||||
"BcdOSLoaderInteger_RemoveMemory" : 0x25000031,
|
||||
"BcdOSLoaderInteger_IncreaseUserVa" : 0x25000032,
|
||||
"BcdOSLoaderBoolean_UseVgaDriver" : 0x26000040,
|
||||
"BcdOSLoaderBoolean_DisableBootDisplay" : 0x26000041,
|
||||
"BcdOSLoaderBoolean_DisableVesaBios" : 0x26000042,
|
||||
"BcdOSLoaderBoolean_DisableVgaMode" : 0x26000043,
|
||||
"BcdOSLoaderInteger_ClusterModeAddressing" : 0x25000050,
|
||||
"BcdOSLoaderBoolean_UsePhysicalDestination" : 0x26000051,
|
||||
"BcdOSLoaderInteger_RestrictApicCluster" : 0x25000052,
|
||||
"BcdOSLoaderBoolean_UseLegacyApicMode" : 0x26000054,
|
||||
"BcdOSLoaderInteger_X2ApicPolicy" : 0x25000055,
|
||||
"BcdOSLoaderBoolean_UseBootProcessorOnly" : 0x26000060,
|
||||
"BcdOSLoaderInteger_NumberOfProcessors" : 0x25000061,
|
||||
"BcdOSLoaderBoolean_ForceMaximumProcessors" : 0x26000062,
|
||||
"BcdOSLoaderBoolean_ProcessorConfigurationFlags" : 0x25000063,
|
||||
"BcdOSLoaderBoolean_MaximizeGroupsCreated" : 0x26000064,
|
||||
"BcdOSLoaderBoolean_ForceGroupAwareness" : 0x26000065,
|
||||
"BcdOSLoaderInteger_GroupSize" : 0x25000066,
|
||||
"BcdOSLoaderInteger_UseFirmwarePciSettings" : 0x26000070,
|
||||
"BcdOSLoaderInteger_MsiPolicy" : 0x25000071,
|
||||
"BcdOSLoaderInteger_SafeBoot" : 0x25000080,
|
||||
"BcdOSLoaderBoolean_SafeBootAlternateShell" : 0x26000081,
|
||||
"BcdOSLoaderBoolean_BootLogInitialization" : 0x26000090,
|
||||
"BcdOSLoaderBoolean_VerboseObjectLoadMode" : 0x26000091,
|
||||
"BcdOSLoaderBoolean_KernelDebuggerEnabled" : 0x260000a0,
|
||||
"BcdOSLoaderBoolean_DebuggerHalBreakpoint" : 0x260000a1,
|
||||
"BcdOSLoaderBoolean_UsePlatformClock" : 0x260000A2,
|
||||
"BcdOSLoaderBoolean_ForceLegacyPlatform" : 0x260000A3,
|
||||
"BcdOSLoaderInteger_TscSyncPolicy" : 0x250000A6,
|
||||
"BcdOSLoaderBoolean_EmsEnabled" : 0x260000b0,
|
||||
"BcdOSLoaderInteger_DriverLoadFailurePolicy" : 0x250000c1,
|
||||
"BcdOSLoaderInteger_BootMenuPolicy" : 0x250000C2,
|
||||
"BcdOSLoaderBoolean_AdvancedOptionsOneTime" : 0x260000C3,
|
||||
"BcdOSLoaderInteger_BootStatusPolicy" : 0x250000E0,
|
||||
"BcdOSLoaderBoolean_DisableElamDrivers" : 0x260000E1,
|
||||
"BcdOSLoaderInteger_HypervisorLaunchType" : 0x250000F0,
|
||||
"BcdOSLoaderBoolean_HypervisorDebuggerEnabled" : 0x260000F2,
|
||||
"BcdOSLoaderInteger_HypervisorDebuggerType" : 0x250000F3,
|
||||
"BcdOSLoaderInteger_HypervisorDebuggerPortNumber" : 0x250000F4,
|
||||
"BcdOSLoaderInteger_HypervisorDebuggerBaudrate" : 0x250000F5,
|
||||
"BcdOSLoaderInteger_HypervisorDebugger1394Channel" : 0x250000F6,
|
||||
"BcdOSLoaderInteger_BootUxPolicy" : 0x250000F7,
|
||||
"BcdOSLoaderString_HypervisorDebuggerBusParams" : 0x220000F9,
|
||||
"BcdOSLoaderInteger_HypervisorNumProc" : 0x250000FA,
|
||||
"BcdOSLoaderInteger_HypervisorRootProcPerNode" : 0x250000FB,
|
||||
"BcdOSLoaderBoolean_HypervisorUseLargeVTlb" : 0x260000FC,
|
||||
"BcdOSLoaderInteger_HypervisorDebuggerNetHostIp" : 0x250000FD,
|
||||
"BcdOSLoaderInteger_HypervisorDebuggerNetHostPort" : 0x250000FE,
|
||||
"BcdOSLoaderInteger_TpmBootEntropyPolicy" : 0x25000100,
|
||||
"BcdOSLoaderString_HypervisorDebuggerNetKey" : 0x22000110,
|
||||
"BcdOSLoaderBoolean_HypervisorDebuggerNetDhcp" : 0x26000114,
|
||||
"BcdOSLoaderInteger_HypervisorIommuPolicy" : 0x25000115,
|
||||
"BcdOSLoaderInteger_XSaveDisable" : 0x2500012b
|
||||
}
|
||||
|
||||
|
||||
def format_value(bcd, bcd_value):
|
||||
|
||||
name = bcd.value_key(bcd_value)
|
||||
(type, length) = bcd.value_type(bcd_value)
|
||||
|
||||
typename = ""
|
||||
str_value = ""
|
||||
if type == REG_SZ:
|
||||
typename = "SZ"
|
||||
str_value = bcd.value_string(bcd_value)
|
||||
elif type == REG_DWORD:
|
||||
typename = "DWORD"
|
||||
dval = bcd.value_dword(bcd_value)
|
||||
|
||||
str_value = hex(dval) + " (" + str(bcd.value_dword(bcd_value)) + ")"
|
||||
elif type == REG_BINARY:
|
||||
typename = "BIN"
|
||||
(length, value) = bcd.value_value(bcd_value)
|
||||
str_value = value.hex()
|
||||
elif type == REG_DWORD_BIG_ENDIAN:
|
||||
typename = "DWORD_BE"
|
||||
elif type == REG_EXPAND_SZ:
|
||||
typename = "EXPAND SZ"
|
||||
elif type == REG_FULL_RESOURCE_DESCRIPTOR:
|
||||
typename = "RES DESC"
|
||||
elif type == REG_LINK:
|
||||
typename = "LINK"
|
||||
elif type == REG_MULTI_SZ:
|
||||
typename = "MULTISZ"
|
||||
(length, str_value) = bcd.value_value(bcd_value)
|
||||
str_value = str_value.decode('utf-16le')
|
||||
str_value = str_value.replace("\0", ";")
|
||||
#value = ";".join("\0".split(value))
|
||||
elif type == REG_NONE:
|
||||
typename = "NONE"
|
||||
elif type == REG_QWORD:
|
||||
typename = "QWORD"
|
||||
elif type == REG_RESOURCE_LIST:
|
||||
typename = "RES LIST"
|
||||
elif type == REG_RESOURCE_REQUIREMENTS_LIST:
|
||||
typename = "REQ LIST"
|
||||
else:
|
||||
typename = str(type)
|
||||
str_value = "???"
|
||||
|
||||
|
||||
return (typename, length, str_value)
|
||||
|
||||
def dump_all(root, depth = 0):
|
||||
|
||||
padding = "\t" * depth
|
||||
|
||||
children = bcd.node_children(root)
|
||||
|
||||
if len(children) > 0:
|
||||
|
||||
for child in children:
|
||||
name = bcd.node_name(child)
|
||||
print(f"{padding}{name}")
|
||||
|
||||
dump_all(child, depth + 1)
|
||||
# print(f"Child: {child}")
|
||||
|
||||
#print(f"Values: {num_vals}")
|
||||
return
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
values = bcd.node_values(root)
|
||||
#print(f"Value list: {values}")
|
||||
|
||||
for v in values:
|
||||
(type_name, length, str_value) = format_value(bcd, v)
|
||||
name = bcd.value_key(v)
|
||||
|
||||
print(f"{padding}{name: <16}: [{type_name: <10}]; ({length: < 4}) {str_value}")
|
||||
|
||||
|
||||
class WindowsBCD:
|
||||
def __init__(self, filename):
|
||||
self.filename = filename
|
||||
self.bcd = Hivex(filename)
|
||||
|
||||
def dump(self, root=None, depth = 0):
|
||||
padding = "\t" * depth
|
||||
|
||||
if root is None:
|
||||
root = self.bcd.root()
|
||||
|
||||
children = self.bcd.node_children(root)
|
||||
|
||||
if len(children) > 0:
|
||||
for child in children:
|
||||
name = self.bcd.node_name(child)
|
||||
print(f"{padding}{name}")
|
||||
|
||||
self.dump(child, depth + 1)
|
||||
return
|
||||
|
||||
values = self.bcd.node_values(root)
|
||||
|
||||
for v in values:
|
||||
(type_name, length, str_value) = format_value(self.bcd, v)
|
||||
name = self.bcd.value_key(v)
|
||||
|
||||
print(f"{padding}{name: <16}: [{type_name: <10}]; ({length: < 4}) {str_value}")
|
||||
|
||||
def list(self):
|
||||
root = self.bcd.root()
|
||||
objects = self.bcd.node_get_child(root, "Objects")
|
||||
|
||||
for child in self.bcd.node_children(objects):
|
||||
entry_id = self.bcd.node_name(child)
|
||||
|
||||
elements = self.bcd.node_get_child(child, "Elements")
|
||||
description_entry = self.bcd.node_get_child(elements, "12000004")
|
||||
|
||||
if description_entry:
|
||||
values = self.bcd.node_values(description_entry)
|
||||
if values:
|
||||
(type_name, length, str_value) = format_value(self.bcd, values[0])
|
||||
print(f"{entry_id}: {str_value}")
|
||||
else:
|
||||
print(f"{entry_id}: [no description value!?]")
|
||||
|
||||
|
||||
appdevice_entry = self.bcd.node_get_child(elements, "11000001")
|
||||
|
||||
if appdevice_entry:
|
||||
values = self.bcd.node_values(appdevice_entry)
|
||||
(length, data) = self.bcd.value_value(values[0])
|
||||
hex = data.hex()
|
||||
print(f"LEN: {length}, HEX: {hex}, RAW: {data}")
|
||||
if len(data) > 10:
|
||||
etype = struct.unpack_from('<I', data, offset = 16)
|
||||
print(f"Type: {etype}")
|
||||
|
||||
|
||||
|
||||
else:
|
||||
print(f"{entry_id}: [no description entry 12000004]")
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="Windows BCD parser",
|
||||
description="Parses the BCD",
|
||||
)
|
||||
|
||||
parser.add_argument("--db", type=str, metavar='BCD file', help="Database to use")
|
||||
parser.add_argument("--dump", action='store_true', help="Dumps the specified database")
|
||||
parser.add_argument("--list", action='store_true', help="Lists boot entries in the specified database")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
bcdobj = WindowsBCD(args.db)
|
||||
|
||||
if args.dump:
|
||||
# "/home/vadim/opengnsys/winboot/boot-copy/EFI/Microsoft/Boot/BCD"
|
||||
#bcd = Hivex(args.dump)
|
||||
|
||||
#root = bcd.root()
|
||||
#dump_all(root)
|
||||
bcdobj.dump()
|
||||
elif args.list:
|
||||
bcdobj.list()
|
|
@ -1,121 +0,0 @@
|
|||
|
||||
import logging
|
||||
import subprocess
|
||||
import re
|
||||
|
||||
# pylint: disable=locally-disabled, line-too-long, logging-fstring-interpolation, too-many-lines
|
||||
|
||||
|
||||
class DiskLibrary:
|
||||
def __init__(self):
|
||||
self.logger = logging.getLogger("OpengnsysDiskLibrary")
|
||||
self.logger.setLevel(logging.DEBUG)
|
||||
|
||||
def split_device_partition(self, device):
|
||||
"""
|
||||
Parses a device file like /dev/sda3 into the root device (/dev/sda) and partition number (3)
|
||||
|
||||
Args:
|
||||
device (str): Device in /dev
|
||||
|
||||
Returns:
|
||||
[base_device, partno]
|
||||
"""
|
||||
|
||||
r = re.compile("^(.*?)(\\d+)$")
|
||||
m = r.match(device)
|
||||
disk = m.group(1)
|
||||
partno = int(m.group(2))
|
||||
|
||||
self.logger.debug(f"{device} parsed into disk device {disk}, partition {partno}")
|
||||
return (disk, partno)
|
||||
|
||||
def get_disk_json_data(self, device):
|
||||
"""
|
||||
Returns the partition JSON data dump for the entire disk, even if a partition is passed.
|
||||
|
||||
This is specifically in the format used by sfdisk.
|
||||
|
||||
Args:
|
||||
device (str): Block device, eg, /dev/sda3
|
||||
|
||||
Returns:
|
||||
str: JSON dump produced by sfdisk
|
||||
"""
|
||||
(disk, partno) = self.split_device_partition(device)
|
||||
|
||||
result = subprocess.run(["/usr/sbin/sfdisk", "--json", disk], check=True, capture_output=True, encoding='utf-8')
|
||||
return result.stdout.strip()
|
||||
|
||||
def get_disk_uuid(self, device):
|
||||
"""
|
||||
Returns the UUID of the disk itself, if there's a GPT partition table.
|
||||
|
||||
Args:
|
||||
device (str): Block device, eg, /dev/sda3
|
||||
|
||||
Returns:
|
||||
str: UUID
|
||||
"""
|
||||
(disk, partno) = self.split_device_partition(device)
|
||||
|
||||
result = subprocess.run(["/usr/sbin/sfdisk", "--disk-id", disk], check=True, capture_output=True, encoding='utf-8')
|
||||
return result.stdout.strip()
|
||||
|
||||
def set_disk_uuid(self, device, uuid):
|
||||
|
||||
(disk, partno) = self.split_device_partition(device)
|
||||
|
||||
subprocess.run(["/usr/sbin/sfdisk", "--disk-id", disk, uuid], check=True, encoding='utf-8')
|
||||
|
||||
|
||||
def get_partition_uuid(self, device):
|
||||
"""
|
||||
Returns the UUID of the partition, if there's a GPT partition table.
|
||||
|
||||
Args:
|
||||
device (str): Block device, eg, /dev/sda3
|
||||
|
||||
Returns:
|
||||
str: UUID
|
||||
"""
|
||||
|
||||
(disk, partno) = self.split_device_partition(device)
|
||||
|
||||
result = subprocess.run(["/usr/sbin/sfdisk", "--part-uuid", disk, str(partno)], check=False, capture_output=True, encoding='utf-8')
|
||||
if result.returncode != 0:
|
||||
# We're using a DOS partition table, no UUID.
|
||||
if "failed to get partition UUID" in result.stderr:
|
||||
return ""
|
||||
raise subprocess.CalledProcessError(result.returncode, result.args)
|
||||
|
||||
return result.stdout.strip()
|
||||
|
||||
def set_partition_uuid(self, device, uuid):
|
||||
(disk, partno) = self.split_device_partition(device)
|
||||
|
||||
subprocess.run(["/usr/sbin/sfdisk", "--part-uuid", disk, str(partno), uuid], check=True, encoding='utf-8')
|
||||
|
||||
def get_partition_type(self, device):
|
||||
"""
|
||||
Returns the type UUID of the partition, if there's a GPT partition table.
|
||||
|
||||
Args:
|
||||
device (str): Block device, eg, /dev/sda3
|
||||
|
||||
Returns:
|
||||
str: UUID
|
||||
"""
|
||||
|
||||
(disk, partno) = self.split_device_partition(device)
|
||||
|
||||
result = subprocess.run(["/usr/sbin/sfdisk", "--part-type", disk, str(partno)], check=True, capture_output=True, encoding='utf-8')
|
||||
return result.stdout.strip()
|
||||
|
||||
def set_partition_type(self, device, uuid):
|
||||
(disk, partno) = self.split_device_partition(device)
|
||||
|
||||
subprocess.run(["/usr/sbin/sfdisk", "--part-type", disk, str(partno), uuid], check=True, encoding='utf-8')
|
||||
|
||||
|
||||
|
|
@ -1,544 +0,0 @@
|
|||
|
||||
import logging
|
||||
import subprocess
|
||||
import os
|
||||
import json
|
||||
import blkid
|
||||
import time
|
||||
|
||||
from GitLib.ntfs import *
|
||||
|
||||
|
||||
|
||||
# pylint: disable=locally-disabled, line-too-long, logging-fstring-interpolation, too-many-lines
|
||||
|
||||
|
||||
class FilesystemLibrary:
|
||||
def __init__(self, ntfs_implementation = NTFSImplementation.KERNEL):
|
||||
self.logger = logging.getLogger("OpengnsysFilesystemLibrary")
|
||||
self.logger.setLevel(logging.DEBUG)
|
||||
|
||||
self.mounts = {}
|
||||
self.base_mount_path = "/mnt"
|
||||
self.ntfs_implementation = ntfs_implementation
|
||||
|
||||
self.update_mounts()
|
||||
|
||||
def _rmmod(self, module):
|
||||
self.logger.debug("Trying to unload module {module}...")
|
||||
subprocess.run(["/usr/sbin/rmmod", module], check=False)
|
||||
|
||||
def _modprobe(self, module):
|
||||
self.logger.debug("Trying to load module {module}...")
|
||||
subprocess.run(["/usr/sbin/modprobe", module], check=True)
|
||||
|
||||
|
||||
# _parse_mounts
|
||||
def update_mounts(self):
|
||||
"""
|
||||
Update the current mount points by parsing the /proc/mounts file.
|
||||
|
||||
This method reads the /proc/mounts file to gather information about
|
||||
the currently mounted filesystems. It stores this information in a
|
||||
dictionary where the keys are the mount points and the values are
|
||||
dictionaries containing details about each filesystem.
|
||||
|
||||
The details stored for each filesystem include:
|
||||
- device: The device file associated with the filesystem.
|
||||
- mountpoint: The directory where the filesystem is mounted.
|
||||
- type: The type of the filesystem (e.g., ext4, vfat).
|
||||
- options: Mount options associated with the filesystem.
|
||||
- dump_freq: The dump frequency for the filesystem.
|
||||
- passno: The pass number for filesystem checks.
|
||||
|
||||
The method also adds an entry for each mount point with a trailing
|
||||
slash to ensure consistency in accessing the mount points.
|
||||
|
||||
Attributes:
|
||||
mounts (dict): A dictionary where keys are mount points and values
|
||||
are dictionaries containing filesystem details.
|
||||
"""
|
||||
filesystems = {}
|
||||
|
||||
self.logger.debug("Parsing /proc/mounts")
|
||||
|
||||
with open("/proc/mounts", 'r', encoding='utf-8') as mounts:
|
||||
for line in mounts:
|
||||
parts = line.split()
|
||||
data = {}
|
||||
data['device'] = parts[0]
|
||||
data['mountpoint'] = parts[1]
|
||||
data['type'] = parts[2]
|
||||
data['options'] = parts[3]
|
||||
data['dump_freq'] = parts[4]
|
||||
data['passno'] = parts[5]
|
||||
|
||||
filesystems[data["mountpoint"]] = data
|
||||
filesystems[data["mountpoint"] + "/"] = data
|
||||
|
||||
self.mounts = filesystems
|
||||
|
||||
def find_mountpoint(self, device):
|
||||
"""
|
||||
Find the mount point for a given device.
|
||||
|
||||
This method checks if the specified device is currently mounted and returns
|
||||
the corresponding mount point if it is found.
|
||||
|
||||
Args:
|
||||
device (str): The path to the device to check.
|
||||
|
||||
Returns:
|
||||
str or None: The mount point of the device if it is mounted, otherwise None.
|
||||
"""
|
||||
norm = os.path.normpath(device)
|
||||
|
||||
self.logger.debug(f"Checking if {device} is mounted")
|
||||
for mountpoint, mount in self.mounts.items():
|
||||
#self.logger.debug(f"Item: {mount}")
|
||||
#self.logger.debug(f"Checking: " + mount['device'])
|
||||
if mount['device'] == norm:
|
||||
return mountpoint
|
||||
|
||||
return None
|
||||
|
||||
def find_device(self, mountpoint):
|
||||
"""
|
||||
Find the device corresponding to a given mount point.
|
||||
|
||||
Args:
|
||||
mountpoint (str): The mount point to search for.
|
||||
|
||||
Returns:
|
||||
str or None: The device corresponding to the mount point if found,
|
||||
otherwise None.
|
||||
"""
|
||||
self.update_mounts()
|
||||
self.logger.debug("Finding device corresponding to mount point %s", mountpoint)
|
||||
if mountpoint in self.mounts:
|
||||
return self.mounts[mountpoint]['device']
|
||||
else:
|
||||
self.logger.warning("Failed to find mountpoint %s", mountpoint)
|
||||
return None
|
||||
|
||||
def is_mounted(self, device = None, mountpoint = None):
|
||||
def is_mounted(self, device=None, mountpoint=None):
|
||||
"""
|
||||
Check if a device or mountpoint is currently mounted.
|
||||
|
||||
Either checking by device or mountpoint is valid.
|
||||
|
||||
Args:
|
||||
device (str, optional): The device to check if it is mounted.
|
||||
Defaults to None.
|
||||
mountpoint (str, optional): The mountpoint to check if it is mounted.
|
||||
Defaults to None.
|
||||
|
||||
Returns:
|
||||
bool: True if the device is mounted or the mountpoint is in the list
|
||||
of mounts, False otherwise.
|
||||
"""
|
||||
self.update_mounts()
|
||||
if device:
|
||||
return not self.find_mountpoint(device) is None
|
||||
else:
|
||||
return mountpoint in self.mounts
|
||||
|
||||
def unmount(self, device = None, mountpoint = None):
|
||||
def unmount(self, device=None, mountpoint=None):
|
||||
"""
|
||||
Unmounts a filesystem.
|
||||
|
||||
This method unmounts a filesystem either by the device name or the mountpoint.
|
||||
If a device is provided, it finds the corresponding mountpoint and unmounts it.
|
||||
If a mountpoint is provided directly, it unmounts the filesystem at that mountpoint.
|
||||
|
||||
Args:
|
||||
device (str, optional): The device name to unmount. Defaults to None.
|
||||
mountpoint (str, optional): The mountpoint to unmount. Defaults to None.
|
||||
|
||||
Raises:
|
||||
subprocess.CalledProcessError: If the unmount command fails.
|
||||
|
||||
Logs:
|
||||
Debug information about the unmounting process.
|
||||
"""
|
||||
if device:
|
||||
self.logger.debug("Finding mountpoint of %s", device)
|
||||
mountpoint = self.find_mountpoint(device)
|
||||
|
||||
if not mountpoint is None:
|
||||
self.logger.debug(f"Unmounting {mountpoint}")
|
||||
|
||||
done = False
|
||||
start_time = time.time()
|
||||
timeout = 60*15
|
||||
|
||||
|
||||
while not done and (time.time() - start_time) < timeout:
|
||||
ret = subprocess.run(["/usr/bin/umount", mountpoint], check=False, capture_output=True, encoding='utf-8')
|
||||
if ret.returncode == 0:
|
||||
done=True
|
||||
else:
|
||||
if "target is busy" in ret.stderr:
|
||||
self.logger.debug("Filesystem busy, waiting. %.1f seconds left", timeout - (time.time() - start_time))
|
||||
time.sleep(0.1)
|
||||
else:
|
||||
raise subprocess.CalledProcessError(ret.returncode, ret.args, output=ret.stdout, stderr=ret.stderr)
|
||||
|
||||
# We've unmounted a new filesystem, update our filesystems list
|
||||
self.update_mounts()
|
||||
else:
|
||||
self.logger.debug(f"{device} is not mounted")
|
||||
|
||||
|
||||
def mount(self, device, mountpoint, filesystem = None):
|
||||
"""
|
||||
Mounts a device to a specified mountpoint.
|
||||
|
||||
Parameters:
|
||||
device (str): The device to be mounted (e.g., '/dev/sda1').
|
||||
mountpoint (str): The directory where the device will be mounted.
|
||||
filesystem (str, optional): The type of filesystem to be used (e.g., 'ext4', 'ntfs'). Defaults to None.
|
||||
|
||||
Raises:
|
||||
subprocess.CalledProcessError: If the mount command fails.
|
||||
|
||||
Logs:
|
||||
Debug information about the mounting process, including the mount command, return code, stdout, and stderr.
|
||||
|
||||
Side Effects:
|
||||
Creates the mountpoint directory if it does not exist.
|
||||
Updates the internal list of mounted filesystems.
|
||||
"""
|
||||
self.logger.debug(f"Mounting {device} at {mountpoint}")
|
||||
|
||||
if not os.path.exists(mountpoint):
|
||||
self.logger.debug(f"Creating directory {mountpoint}")
|
||||
os.mkdir(mountpoint)
|
||||
|
||||
mount_cmd = ["/usr/bin/mount"]
|
||||
|
||||
if not filesystem is None:
|
||||
mount_cmd = mount_cmd + ["-t", filesystem]
|
||||
|
||||
mount_cmd = mount_cmd + [device, mountpoint]
|
||||
|
||||
self.logger.debug(f"Mount command: {mount_cmd}")
|
||||
result = subprocess.run(mount_cmd, check=True, capture_output = True)
|
||||
|
||||
self.logger.debug(f"retorno: {result.returncode}")
|
||||
self.logger.debug(f"stdout: {result.stdout}")
|
||||
self.logger.debug(f"stderr: {result.stderr}")
|
||||
|
||||
# We've mounted a new filesystem, update our filesystems list
|
||||
self.update_mounts()
|
||||
|
||||
def ensure_mounted(self, device):
|
||||
"""
|
||||
Ensure that the given device is mounted.
|
||||
|
||||
This method attempts to mount the specified device to a path derived from
|
||||
the base mount path and the device's basename. If the device is of type NTFS,
|
||||
it uses the NTFSLibrary to handle the mounting process. For other filesystem
|
||||
types, it uses a generic mount method.
|
||||
|
||||
Args:
|
||||
device (str): The path to the device that needs to be mounted.
|
||||
|
||||
Returns:
|
||||
str: The path where the device is mounted.
|
||||
|
||||
Logs:
|
||||
- Info: When starting the mounting process.
|
||||
- Debug: Various debug information including the mount path, filesystem type,
|
||||
and success message.
|
||||
|
||||
Raises:
|
||||
OSError: If there is an error creating the mount directory or mounting the device.
|
||||
"""
|
||||
|
||||
self.logger.info("Mounting %s", device)
|
||||
|
||||
self.unmount(device = device)
|
||||
path = os.path.join(self.base_mount_path, os.path.basename(device))
|
||||
|
||||
self.logger.debug(f"Will mount repo at {path}")
|
||||
if not os.path.exists(path):
|
||||
os.mkdir(path)
|
||||
|
||||
if self.filesystem_type(device) == "ntfs":
|
||||
self.logger.debug("Handing a NTFS filesystem")
|
||||
|
||||
self._modprobe("ntfs3")
|
||||
self.ntfsfix(device)
|
||||
|
||||
ntfs = NTFSLibrary(self.ntfs_implementation)
|
||||
ntfs.mount_filesystem(device, path)
|
||||
self.update_mounts()
|
||||
|
||||
else:
|
||||
self.logger.debug("Handling a non-NTFS filesystem")
|
||||
self.mount(device, path)
|
||||
|
||||
self.logger.debug("Successfully mounted at %s", path)
|
||||
return path
|
||||
|
||||
|
||||
def filesystem_type(self, device = None, mountpoint = None):
|
||||
"""
|
||||
Determine the filesystem type of a given device or mountpoint.
|
||||
|
||||
Args:
|
||||
device (str, optional): The device to probe. If not provided, the device
|
||||
will be determined based on the mountpoint.
|
||||
mountpoint (str, optional): The mountpoint to find the device for. This
|
||||
is used only if the device is not provided.
|
||||
|
||||
Returns:
|
||||
str: The filesystem type of the device.
|
||||
|
||||
Raises:
|
||||
KeyError: If the filesystem type cannot be determined from the probe.
|
||||
|
||||
Logs:
|
||||
Debug: Logs the process of finding the device, probing the device, and
|
||||
the determined filesystem type.
|
||||
"""
|
||||
|
||||
if device is None:
|
||||
self.logger.debug("Finding device for mountpoint %s", mountpoint)
|
||||
device = self.find_device(mountpoint)
|
||||
|
||||
self.logger.debug(f"Probing {device}")
|
||||
|
||||
pr = blkid.Probe()
|
||||
pr.set_device(device)
|
||||
pr.enable_superblocks(True)
|
||||
pr.set_superblocks_flags(blkid.SUBLKS_TYPE | blkid.SUBLKS_USAGE | blkid.SUBLKS_UUID | blkid.SUBLKS_UUIDRAW | blkid.SUBLKS_LABELRAW)
|
||||
pr.do_safeprobe()
|
||||
|
||||
fstype = pr["TYPE"].decode('utf-8')
|
||||
self.logger.debug(f"FS type is {fstype}")
|
||||
|
||||
return fstype
|
||||
|
||||
def is_filesystem(self, path):
|
||||
"""
|
||||
Check if the given path is a filesystem root.
|
||||
|
||||
Args:
|
||||
path (str): The path to check.
|
||||
|
||||
Returns:
|
||||
bool: True if the path is a filesystem root, False otherwise.
|
||||
"""
|
||||
|
||||
# This is just an alias for better code readability
|
||||
return self.is_mounted(mountpoint = path)
|
||||
|
||||
def create_filesystem(self, fs_type = None, fs_uuid = None, device = None):
|
||||
"""
|
||||
Create a filesystem on the specified device.
|
||||
|
||||
Parameters:
|
||||
fs_type (str): The type of filesystem to create (e.g., 'ntfs', 'ext4', 'xfs', 'btrfs').
|
||||
fs_uuid (str): The UUID to assign to the filesystem.
|
||||
device (str): The device on which to create the filesystem (e.g., '/dev/sda1').
|
||||
|
||||
Raises:
|
||||
RuntimeError: If the filesystem type is not recognized or if the filesystem creation command fails.
|
||||
|
||||
"""
|
||||
|
||||
self.logger.info(f"Creating filesystem {fs_type} with UUID {fs_uuid} in {device}")
|
||||
|
||||
if fs_type == "ntfs" or fs_type == "ntfs3":
|
||||
self.logger.debug("Creating NTFS filesystem")
|
||||
ntfs = NTFSLibrary(self.ntfs_implementation)
|
||||
ntfs.create_filesystem(device, "NTFS")
|
||||
ntfs.modify_uuid(device, fs_uuid)
|
||||
|
||||
else:
|
||||
command = [f"/usr/sbin/mkfs.{fs_type}"]
|
||||
command_args = []
|
||||
|
||||
if fs_type == "ext4" or fs_type == "ext3":
|
||||
command_args = ["-U", fs_uuid, "-F", device]
|
||||
elif fs_type == "xfs":
|
||||
command_args = ["-m", f"uuid={fs_uuid}", "-f", device]
|
||||
elif fs_type == "btrfs":
|
||||
command_args = ["-U", fs_uuid, "-f", device]
|
||||
else:
|
||||
raise RuntimeError(f"Don't know how to create filesystem of type {fs_type}")
|
||||
|
||||
command = command + command_args
|
||||
|
||||
self.logger.debug(f"Creating Linux filesystem of type {fs_type} on {device}, command {command}")
|
||||
result = subprocess.run(command, check = True, capture_output=True)
|
||||
|
||||
self.logger.debug(f"retorno: {result.returncode}")
|
||||
self.logger.debug(f"stdout: {result.stdout}")
|
||||
self.logger.debug(f"stderr: {result.stderr}")
|
||||
|
||||
|
||||
|
||||
def mklostandfound(self, path):
|
||||
"""
|
||||
Recreate the lost+found if necessary.
|
||||
|
||||
When cloning at the root of a filesystem, cleaning the contents
|
||||
removes the lost+found directory. This is a special directory that requires the use of
|
||||
a tool to recreate it.
|
||||
|
||||
It may fail if the filesystem does not need it. We consider this harmless and ignore it.
|
||||
|
||||
The command is entirely skipped on NTFS, as mklost+found may malfunction if run on it,
|
||||
and has no useful purpose.
|
||||
"""
|
||||
if self.is_filesystem(path):
|
||||
if self.filesystem_type(mountpoint=path) == "ntfs":
|
||||
self.logger.debug("Not running mklost+found on NTFS")
|
||||
return
|
||||
|
||||
|
||||
curdir = os.getcwd()
|
||||
result = None
|
||||
|
||||
try:
|
||||
self.logger.debug(f"Re-creating lost+found in {path}")
|
||||
os.chdir(path)
|
||||
result = subprocess.run(["/usr/sbin/mklost+found"], check=True, capture_output=True)
|
||||
except subprocess.SubprocessError as e:
|
||||
self.logger.warning(f"Error running mklost+found: {e}")
|
||||
|
||||
if result:
|
||||
self.logger.debug(f"retorno: {result.returncode}")
|
||||
self.logger.debug(f"stdout: {result.stdout}")
|
||||
self.logger.debug(f"stderr: {result.stderr}")
|
||||
|
||||
os.chdir(curdir)
|
||||
|
||||
def ntfsfix(self, device):
|
||||
"""
|
||||
Run the ntfsfix command on the specified device.
|
||||
|
||||
This method uses the ntfsfix utility to fix common NTFS problems on the given device.
|
||||
|
||||
This allows mounting an unclean NTFS filesystem.
|
||||
|
||||
Args:
|
||||
device (str): The path to the device to be fixed.
|
||||
|
||||
Raises:
|
||||
subprocess.CalledProcessError: If the ntfsfix command fails.
|
||||
"""
|
||||
self.logger.debug(f"Running ntfsfix on {device}")
|
||||
subprocess.run(["/usr/bin/ntfsfix", "-d", device], check=True)
|
||||
|
||||
|
||||
def unload_ntfs(self):
|
||||
"""
|
||||
Unloads the NTFS filesystem module.
|
||||
|
||||
This is a function added as a result of NTFS kernel module troubleshooting,
|
||||
to try to ensure that NTFS code is only active as long as necessary.
|
||||
|
||||
The module is internally loaded as needed, so there's no load_ntfs function.
|
||||
|
||||
It may be removed in the future.
|
||||
|
||||
Raises:
|
||||
RuntimeError: If the module cannot be removed.
|
||||
"""
|
||||
self._rmmod("ntfs3")
|
||||
|
||||
def find_boot_device(self):
|
||||
"""
|
||||
Searches for the EFI boot partition on the system.
|
||||
|
||||
This method scans the system's partitions to locate the EFI boot partition,
|
||||
which is identified by the GUID "C12A7328-F81F-11D2-BA4B-00A0C93EC93B".
|
||||
|
||||
Returns:
|
||||
str: The device node of the EFI partition if found, otherwise None.
|
||||
|
||||
Logs:
|
||||
- Debug messages indicating the progress of the search.
|
||||
- A warning message if the EFI partition is not found.
|
||||
"""
|
||||
disks = []
|
||||
|
||||
self.logger.debug("Looking for EFI partition")
|
||||
with open("/proc/partitions", "r", encoding='utf-8') as partitions_file:
|
||||
line_num=0
|
||||
for line in partitions_file:
|
||||
if line_num >=2:
|
||||
data = line.split()
|
||||
disk = data[3]
|
||||
disks.append(disk)
|
||||
self.logger.debug(f"Disk: {disk}")
|
||||
|
||||
line_num = line_num + 1
|
||||
|
||||
for disk in disks:
|
||||
self.logger.debug("Loading partitions for disk %s", disk)
|
||||
#disk_json_data = subprocess.run(["/usr/sbin/sfdisk", "-J", f"/dev/{disk}"], check=False, capture_output=True)
|
||||
sfdisk_out = subprocess.run(["/usr/sbin/sfdisk", "-J", f"/dev/{disk}"], check=False, capture_output=True)
|
||||
|
||||
if sfdisk_out.returncode == 0:
|
||||
disk_json_data = sfdisk_out.stdout
|
||||
disk_data = json.loads(disk_json_data)
|
||||
|
||||
for part in disk_data["partitiontable"]["partitions"]:
|
||||
self.logger.debug("Checking partition %s", part)
|
||||
if part["type"] == "C12A7328-F81F-11D2-BA4B-00A0C93EC93B":
|
||||
self.logger.debug("EFI partition found at %s", part["node"])
|
||||
return part["node"]
|
||||
else:
|
||||
self.logger.debug("sfdisk returned with code %i, error %s", sfdisk_out.returncode, sfdisk_out.stderr)
|
||||
|
||||
|
||||
self.logger.warning("Failed to find EFI partition!")
|
||||
|
||||
def temp_unmount(self, mountpoint):
|
||||
"""
|
||||
Temporarily unmounts the filesystem at the given mountpoint.
|
||||
|
||||
This method finds the device associated with the specified mountpoint,
|
||||
and returns the information to remount it with temp_remount.
|
||||
|
||||
The purpose of this function is to temporarily unmount a filesystem for
|
||||
actions like fsck, and to mount it back afterwards.
|
||||
|
||||
Args:
|
||||
mountpoint (str): The mountpoint of the filesystem to unmount.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary containing the information needed to remount the filesystem.
|
||||
"""
|
||||
device = self.find_device(mountpoint)
|
||||
fs = self.filesystem_type(mountpoint = mountpoint)
|
||||
|
||||
data = {"mountpoint" : mountpoint, "device" :device, "filesystem" : fs}
|
||||
|
||||
self.logger.debug("Temporarily unmounting device %s, mounted on %s, fs type %s", mountpoint, device, fs)
|
||||
|
||||
self.unmount(mountpoint = mountpoint)
|
||||
return data
|
||||
|
||||
def temp_remount(self, unmount_data):
|
||||
"""
|
||||
Remounts a filesystem unmounted with temp_unmount
|
||||
|
||||
This method remounts a filesystem using the data provided by temp_unmount
|
||||
|
||||
Args:
|
||||
unmount_data (dict): A dictionary containing the data needed to remount the filesystem.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
self.logger.debug("Remounting temporarily unmounted device %s on %s, fs type %s", unmount_data["device"], unmount_data["mountpoint"], unmount_data["filesystem"])
|
||||
self.mount(device = unmount_data["device"], mountpoint=unmount_data["mountpoint"], filesystem=unmount_data["filesystem"])
|
|
@ -1,22 +0,0 @@
|
|||
|
||||
|
||||
def parse_kernel_cmdline():
|
||||
"""Parse the kernel arguments to obtain configuration parameters in Oglive
|
||||
|
||||
OpenGnsys passes data in the kernel arguments, for example:
|
||||
[...] group=Aula_virtual ogrepo=192.168.2.1 oglive=192.168.2.1 [...]
|
||||
|
||||
Returns:
|
||||
dict: Dict of configuration parameters and their values.
|
||||
"""
|
||||
params = {}
|
||||
|
||||
with open("/proc/cmdline", encoding='utf-8') as cmdline:
|
||||
line = cmdline.readline()
|
||||
parts = line.split()
|
||||
for part in parts:
|
||||
if "=" in part:
|
||||
key, value = part.split("=")
|
||||
params[key] = value
|
||||
|
||||
return params
|
|
@ -1,111 +0,0 @@
|
|||
|
||||
import logging
|
||||
import subprocess
|
||||
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class NTFSImplementation(Enum):
|
||||
KERNEL = 1
|
||||
NTFS3G = 2
|
||||
|
||||
|
||||
class NTFSLibrary:
|
||||
"""
|
||||
A library for managing NTFS filesystems.
|
||||
|
||||
Attributes:
|
||||
logger (logging.Logger): Logger for the class.
|
||||
implementation (NTFSImplementation): The implementation to use for mounting NTFS filesystems.
|
||||
"""
|
||||
|
||||
def __init__(self, implementation):
|
||||
"""
|
||||
Initializes the instance with the given implementation.
|
||||
|
||||
Args:
|
||||
implementation: The implementation to be used by the instance.
|
||||
|
||||
Attributes:
|
||||
logger (logging.Logger): Logger instance for the class, set to debug level.
|
||||
implementation: The implementation provided during initialization.
|
||||
"""
|
||||
self.logger = logging.getLogger("NTFSLibrary")
|
||||
self.logger.setLevel(logging.DEBUG)
|
||||
self.implementation = implementation
|
||||
|
||||
self.logger.debug("Initializing")
|
||||
|
||||
def create_filesystem(self, device, label):
|
||||
"""
|
||||
Creates an NTFS filesystem on the specified device with the given label.
|
||||
|
||||
Args:
|
||||
device (str): The device path where the NTFS filesystem will be created.
|
||||
label (str): The label to assign to the NTFS filesystem.
|
||||
|
||||
Returns:
|
||||
None
|
||||
|
||||
Logs:
|
||||
Logs the creation process with the device and label information.
|
||||
"""
|
||||
self.logger.info(f"Creating NTFS in {device} with label {label}")
|
||||
|
||||
subprocess.run(["/usr/sbin/mkntfs", device, "-Q", "-L", label], check=True)
|
||||
|
||||
|
||||
def mount_filesystem(self, device, mountpoint):
|
||||
"""
|
||||
Mounts a filesystem on the specified mountpoint using the specified NTFS implementation.
|
||||
|
||||
Args:
|
||||
device (str): The device path to be mounted (e.g., '/dev/sda1').
|
||||
mountpoint (str): The directory where the device will be mounted.
|
||||
|
||||
Raises:
|
||||
ValueError: If the NTFS implementation is unknown.
|
||||
|
||||
"""
|
||||
self.logger.info(f"Mounting {device} in {mountpoint} using implementation {self.implementation}")
|
||||
if self.implementation == NTFSImplementation.KERNEL:
|
||||
subprocess.run(["/usr/bin/mount", "-t", "ntfs3", device, mountpoint], check = True)
|
||||
elif self.implementation == NTFSImplementation.NTFS3G:
|
||||
subprocess.run(["/usr/bin/ntfs-3g", device, mountpoint], check = True)
|
||||
else:
|
||||
raise ValueError("Unknown NTFS implementation: {self.implementation}")
|
||||
|
||||
def modify_uuid(self, device, uuid):
|
||||
"""
|
||||
Modify the UUID of an NTFS device.
|
||||
|
||||
This function changes the UUID of the specified NTFS device to the given UUID.
|
||||
It reads the current UUID from the device, logs the change, and writes the new UUID.
|
||||
|
||||
Args:
|
||||
device (str): The path to the NTFS device file.
|
||||
uuid (str): The new UUID to be set, in hexadecimal string format.
|
||||
|
||||
Raises:
|
||||
IOError: If there is an error opening or writing to the device file.
|
||||
"""
|
||||
|
||||
ntfs_uuid_offset = 0x48
|
||||
ntfs_uuid_length = 8
|
||||
|
||||
binary_uuid = bytearray.fromhex(uuid)
|
||||
binary_uuid.reverse()
|
||||
|
||||
self.logger.info(f"Changing UUID on {device} to {uuid}")
|
||||
with open(device, 'r+b') as ntfs_dev:
|
||||
self.logger.debug("Reading %i bytes from offset %i", ntfs_uuid_length, ntfs_uuid_offset)
|
||||
|
||||
ntfs_dev.seek(ntfs_uuid_offset)
|
||||
prev_uuid = bytearray(ntfs_dev.read(ntfs_uuid_length))
|
||||
prev_uuid.reverse()
|
||||
prev_uuid_hex = bytearray.hex(prev_uuid)
|
||||
self.logger.debug(f"Previous UUID: {prev_uuid_hex}")
|
||||
|
||||
self.logger.debug("Writing...")
|
||||
ntfs_dev.seek(ntfs_uuid_offset)
|
||||
ntfs_dev.write(binary_uuid)
|
|
@ -224,6 +224,7 @@ def ogUcastSendFile (disk=None, par=None, container=None, file=None, sess=None):
|
|||
return
|
||||
|
||||
path2 = FileLib.ogGetPath (file=source)
|
||||
print (f'nati path2 ({path2})')
|
||||
if not path2:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'device or file {dev_err} not found')
|
||||
return
|
||||
|
@ -482,6 +483,7 @@ def ogMcastSendFile (disk=None, par=None, container=None, file=None, sess=None):
|
|||
return
|
||||
|
||||
path2 = FileLib.ogGetPath (file=source)
|
||||
print (f'nati path2 ({path2})')
|
||||
if not path2:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'device or file {dev_err} not found')
|
||||
return
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
bootOs
|
|
@ -0,0 +1 @@
|
|||
bootOs
|
|
@ -50,8 +50,6 @@ def main (NDISK, NPART, SIZE, MOUNT):
|
|||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_CACHE, 'failed to create cache')
|
||||
return False
|
||||
DiskLib.ogUpdatePartitionTable()
|
||||
else:
|
||||
print("[10] Partición de caché solicitada es del mismo tamaño que la existente, ignorar.")
|
||||
|
||||
# Si caché no montada y no formateada o cambia el tamaño: formatear.
|
||||
cache = CacheLib.ogFindCache()
|
||||
|
|
Loading…
Reference in New Issue