Compare commits
30 Commits
Author | SHA1 | Date |
---|---|---|
|
c33c9ec1af | |
|
6617bace74 | |
|
a560380b81 | |
|
acaf67f486 | |
|
5cf92d6367 | |
|
c2d04ca39f | |
|
4432b60326 | |
|
87b566532c | |
|
c5db321d93 | |
|
3d692f54a5 | |
|
e529768257 | |
|
8029d469a7 | |
|
73721d70f7 | |
|
83c1c7763a | |
|
9e7fda8944 | |
|
df36d74d7c | |
|
38be98d9f1 | |
|
36a8277aab | |
|
cf5ec4c214 | |
|
0d28787318 | |
|
9cad17e4f4 | |
|
a7f4d767f5 | |
|
588ed96098 | |
|
87adfeda1c | |
|
6e806424cc | |
|
334f961e4c | |
|
8ae6b503a6 | |
|
f7569ffe4d | |
|
f97f800919 | |
|
0f0d62c655 |
36
CHANGELOG.md
36
CHANGELOG.md
|
@ -5,6 +5,42 @@ 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.27.0] - 2025-07-16
|
||||
|
||||
### Added
|
||||
|
||||
- Add python init scripts
|
||||
|
||||
## [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
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
#!/usr/bin/python3
|
||||
# Proceso general de arranque de OpenGnsys Client.
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import ogGlobals
|
||||
from NetLib import ogGetIpAddress
|
||||
|
||||
ogstatus = os.environ.get ('ogstatus', '')
|
||||
ogcore = os.environ.get ('ogcore', '')
|
||||
oglog = os.environ.get ('oglog', '')
|
||||
oggroup = os.environ.get ('OGGROUP', '')
|
||||
ogactiveadmin = os.environ.get ('ogactiveadmin', '')
|
||||
LANG = os.environ.get ('LANG', 'es_ES')
|
||||
LANG = LANG[0:LANG.index('_')]
|
||||
|
||||
LOGLEVEL=5
|
||||
|
||||
# Matando plymount para inicir browser o shell
|
||||
subprocess.run (['pkill', '-9', 'plymouthd'])
|
||||
|
||||
# Arranque de OpenGnsys Client daemon (socket).
|
||||
print (ogGlobals.lang.MSG_LAUNCHCLIENT)
|
||||
# Indicar fichero de teclado de Qt para el idioma especificado (tipo "es.qmap").
|
||||
if os.path.exists (f'/usr/local/etc/{LANG}.qmap'):
|
||||
os.environ['QWS_KEYBOARD'] = f'TTY:keymap=/usr/local/etc/{LANG}.qmap'
|
||||
|
||||
if os.path.exists ('/usr/share/OGAgent/opengnsys/linux/OGAgentService.py') and ogstatus != 'offline':
|
||||
os.chdir ('/usr/share/OGAgent')
|
||||
os.environ['OGAGENTCFG_OGCORE_IP'] = ogcore
|
||||
os.environ['OGAGENTCFG_OGLOG_IP'] = oglog
|
||||
os.environ['OGAGENTCFG_URLMENU_SCHEME'] = 'http'
|
||||
os.environ['OGAGENTCFG_URLMENU_IP'] = '127.0.0.1'
|
||||
os.environ['OGAGENTCFG_URLMENU_PORT'] = '81'
|
||||
subprocess.run (['python3', '-m', 'opengnsys.linux.OGAgentService', 'fg'])
|
||||
else:
|
||||
ip = ogGetIpAddress()
|
||||
OGMENU = ''
|
||||
for FILE in [index, oggroup, ip]:
|
||||
if not FILE: continue
|
||||
m = f'{ogGlobals.OGCAC}/menus/{FILE}.html'
|
||||
if os.path.exists (m): OGMENU = m
|
||||
subprocess.run ([f'{ogGlobals.OPENGNSYS}/bin/launch_browser', m])
|
||||
|
||||
# Si fallo en cliente y modo "admin", cargar shell; si no, salir.
|
||||
if ogactiveadmin == 'true':
|
||||
subprocess.run (['bash'])
|
|
@ -0,0 +1,43 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
## early init
|
||||
import os
|
||||
import sys
|
||||
OPENGNSYS = os.environ.get ('OPENGNSYS', '/opt/opengnsys')
|
||||
os.environ['PYTHONPATH'] = f'{OPENGNSYS}/lib/python3'
|
||||
sys.path.insert (0, os.environ['PYTHONPATH'])
|
||||
## end
|
||||
|
||||
import subprocess
|
||||
|
||||
import ogGlobals
|
||||
from InitLib import loadenviron, write_profile, clean_esp, fileslinks, loadmodules, metadevs, mountrepo, poweroff, filebeat, stunnel, dbus, otherservices, runhttplog
|
||||
|
||||
IPV4ADDR = os.environ.get ('IPV4ADDR', '')
|
||||
OG_IP = os.environ.get ('OG_IP', '')
|
||||
|
||||
loadenviron()
|
||||
write_profile()
|
||||
|
||||
# Funciones de inicio.
|
||||
clean_esp()
|
||||
fileslinks()
|
||||
loadmodules()
|
||||
metadevs()
|
||||
mountrepo()
|
||||
poweroff()
|
||||
filebeat()
|
||||
stunnel()
|
||||
dbus()
|
||||
otherservices()
|
||||
runhttplog()
|
||||
|
||||
if IPV4ADDR and os.path.exists (f'{ogGlobals.OGETC}/init/{IPV4ADDR}.sh'):
|
||||
if OG_IP: subprocess.run ([f'{ogGlobals.OGETC}/init/{OG_IP}.sh'])
|
||||
|
||||
elif os.path.exists (f'{ogGlobals.OGETC}/init.py'):
|
||||
subprocess.run ([f'{ogGlobals.OGETC}/init.py'])
|
||||
|
||||
else:
|
||||
print ('No se ha encontrado script de inicio')
|
||||
subprocess.run (['halt'])
|
|
@ -1,5 +1,12 @@
|
|||
#!/bin/bash
|
||||
|
||||
if grep -q pyinit=true /proc/cmdline; then
|
||||
echo "python init"
|
||||
exec /opt/opengnsys/etc/preinit/default.py
|
||||
else
|
||||
echo "shell init"
|
||||
fi
|
||||
|
||||
# Cargar entorno de OpenGnsys
|
||||
set -a
|
||||
source /opt/opengnsys/etc/preinit/loadenviron.sh
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
#!/bin/bash
|
||||
|
||||
F=/etc/filebeat/filebeat.yml
|
||||
OGLOG_PORT=9200
|
||||
OPENSEARCH_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__/$OGLOG_PORT/g" \
|
||||
-e "s/__OPENSEARCH_PASSWORD__/$PASS/g" \
|
||||
sed -i -e "s/__OGLOG_IP__/$oglog/g" \
|
||||
-e "s/__OGLOG_PORT__/$OPENSEARCH_PORT/g" \
|
||||
-e "s/__OPENSEARCH_PASSWORD__/$PASS/g" \
|
||||
$F
|
||||
unset PASS
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
|
||||
import ogGlobals
|
||||
import SystemLib
|
||||
|
@ -34,12 +33,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).
|
||||
|
@ -51,12 +50,13 @@ 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.
|
||||
tbprm = pparam.split ('*')
|
||||
pparams = pparam.split ('*')
|
||||
dis = tch = None
|
||||
for item in tbprm:
|
||||
for item in pparams:
|
||||
if '=' not in item: continue
|
||||
|
||||
k, v = item.split ('=', 1)
|
||||
|
@ -74,10 +74,13 @@ if dis is None:
|
|||
tbp = [] # Valores de configuración (parámetros para ogCreatePartitions)
|
||||
tbf = {} # Tabla de formateo
|
||||
|
||||
tbprm = sparam.split('%')
|
||||
sparams = sparam.split('%')
|
||||
|
||||
maxp=0
|
||||
for item in tbprm:
|
||||
sum_tam = 0
|
||||
do_sum_tam = True
|
||||
cache_seen = extended_seen = efi_seen = False
|
||||
for item in sparams:
|
||||
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
|
||||
|
@ -93,7 +96,7 @@ for item in tbprm:
|
|||
if 'par' == k: par = int (v)
|
||||
elif 'cpt' == k: cpt = v
|
||||
elif 'sfi' == k: sfi = v
|
||||
elif 'tam' == k: tam = v
|
||||
elif 'tam' == k: tam = int (v)
|
||||
elif 'ope' == k: ope = int (v)
|
||||
|
||||
missing_params = []
|
||||
|
@ -106,10 +109,29 @@ for item in tbprm:
|
|||
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']:
|
||||
|
@ -118,7 +140,88 @@ for item in tbprm:
|
|||
if par > maxp: maxp = par
|
||||
|
||||
if tch is None:
|
||||
tch = '0'
|
||||
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)
|
||||
|
||||
#____________________________________________________
|
||||
#
|
||||
|
@ -133,53 +236,46 @@ SystemLib.ogEcho (['session', 'log'], None, f'[10] {ogGlobals.lang.MSG_HELP_ogUn
|
|||
FileSystemLib.ogUnmountAll (dis)
|
||||
CacheLib.ogUnmountCache()
|
||||
|
||||
# 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:
|
||||
if recreate_partition_table:
|
||||
DiskLib.ogDeletePartitionTable (dis)
|
||||
SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogUpdatePartitionTable'])
|
||||
DiskLib.ogCreatePartitionTable (dis, ptt)
|
||||
|
||||
# Inicia la cache.
|
||||
if 'CACHE' in sparam:
|
||||
if is_there_cache:
|
||||
SystemLib.ogEcho (['session', 'log'], None, f'[30] {ogGlobals.lang.MSG_HELP_ogCreateCache}')
|
||||
SystemLib.ogEcho (['session', 'log'], None, f' initCache {tch}')
|
||||
rc = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGSCRIPTS}/initCache', tch])
|
||||
SystemLib.ogEcho (['session', 'log'], None, f' initCache.py {dis} {tch}')
|
||||
rc = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGSCRIPTS}/initCache.py', str (dis), str (tch)])
|
||||
if not rc:
|
||||
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_CACHE, f'initCache failed')
|
||||
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_CACHE, f'initCache.py failed')
|
||||
sys.exit (1)
|
||||
|
||||
# Definir particionado.
|
||||
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'])
|
||||
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'])
|
||||
|
||||
# Formatear particiones
|
||||
SystemLib.ogEcho (['session', 'log'], None, f'[70] {ogGlobals.lang.MSG_HELP_ogFormat}')
|
||||
retval = 0
|
||||
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
|
||||
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)
|
||||
|
||||
SystemLib.ogEcho (['session', 'log'], None, f'{ogGlobals.lang.MSG_INTERFACE_END} {retval}')
|
||||
|
||||
#___________________________________________________________________
|
||||
#
|
||||
# Retorno
|
||||
#___________________________________________________________________
|
||||
|
||||
sys.exit (0)
|
||||
|
|
|
@ -1,36 +1,78 @@
|
|||
#!/usr/bin/env python3
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
import resource
|
||||
import logging
|
||||
|
||||
|
||||
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
|
||||
from GitLib import OpengnsysGitLibrary, NTFSImplementation, OgProgressPrinterWeb
|
||||
|
||||
|
||||
def create_image(disk_num, partition_num, repo, image_name):
|
||||
def create_image(disk_num, partition_num, repo, image_name, tagName):
|
||||
|
||||
ntfs_impl = NTFSImplementation.NTFS3G
|
||||
og_git = OpengnsysGitLibrary(ntfs_implementation = ntfs_impl)
|
||||
device = og_git._runBashFunction("ogDiskToDev", [str(disk_num), str(partition_num)])
|
||||
og_git.initRepo(device, image_name)
|
||||
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
|
||||
|
||||
|
||||
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(OG_ERR_FORMAT, "Incorrect number of arguments"))
|
||||
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.
|
||||
|
||||
|
||||
disk_num, partition_num, image_name, repo, tag = sys.argv[1:6]
|
||||
|
||||
retval = create_image(disk_num, partition_num, repo, image_name)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
|
||||
sys.exit(retval)
|
||||
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
#!/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,32 +1,65 @@
|
|||
#!/usr/bin/env python3
|
||||
import sys
|
||||
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 resource
|
||||
import logging
|
||||
|
||||
import NetLib
|
||||
import ogGlobals
|
||||
import SystemLib
|
||||
from gitlib import OpengnsysGitLibrary, NTFSImplementation
|
||||
import DiskLib
|
||||
|
||||
from GitLib import OpengnsysGitLibrary, NTFSImplementation, OgProgressPrinterWeb
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 4:
|
||||
print("Usage: python RestaurarImagenGit.py <disk> <partition> <repo> <boot_device>")
|
||||
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>")
|
||||
sys.exit(1)
|
||||
|
||||
disk = sys.argv[1]
|
||||
partition = sys.argv[2]
|
||||
repo = sys.argv[3]
|
||||
boot_device = sys.argv[4]
|
||||
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")
|
||||
|
||||
|
||||
|
||||
|
||||
ntfs_impl = NTFSImplementation.NTFS3G
|
||||
og_git = OpengnsysGitLibrary(ntfs_implementation = ntfs_impl)
|
||||
og_git.progress_callback = OgProgressPrinterWeb()
|
||||
|
||||
device = og_git._runBashFunction("ogDiskToDev", [str(disk), str(partition)])
|
||||
device = DiskLib.ogDiskToDev(disk, partition)
|
||||
|
||||
og_git.cloneRepo(repo, device, boot_device)
|
||||
og_git.cloneRepo(repo, device, device)
|
||||
|
||||
logger.info("RestaurarImagenGit Finished.")
|
||||
|
||||
|
||||
|
|
|
@ -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}'
|
||||
cp_cmd = f'cp {ogGlobals.OGLIB}/grub4dos/* {mntdir}' ## shutil sucks a bit for copying both files and dirs
|
||||
subprocess.run (cp_cmd, shell=True)
|
||||
disk0 = int(disk)-1
|
||||
par0 = int(par)-1
|
||||
|
|
|
@ -37,16 +37,15 @@ 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 = 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
|
||||
IOSIZE = DiskLib.ogGetIoSize (ndsk)
|
||||
if not IOSIZE:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'Failed to get disk sector size')
|
||||
return None
|
||||
START = 0
|
||||
if 4096 == IOSIZE:
|
||||
END -= 8192
|
||||
|
@ -70,7 +69,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_GENERIC, f'size ({SIZE}) < minsize ({MINSIZE}) or size > maxsize ({MAXSIZE}) or start ({START}) < endprevpart ({ENDPREVPART})')
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'size ({SIZE}) < minsize ({MINSIZE}) or size ({SIZE}) > maxsize ({MAXSIZE}) or start ({START}) < endprevpart ({ENDPREVPART})')
|
||||
return None
|
||||
|
||||
# Desmontar todos los sistemas de archivos del disco.
|
||||
|
@ -90,27 +89,32 @@ 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()
|
||||
# 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}'])
|
||||
|
||||
ID = DiskLib.ogTypeToId ('LINUX', 'GPT_GUID')
|
||||
sfdisk_line = f'{DISK}{NVME_PREFIX}{part} : start= {START}, size= {SIZE}, type={ID}, name=CACHE'
|
||||
elif 'MSDOS' == get_ptt:
|
||||
# Si la tabla de particiones no es valida, volver a generarla.
|
||||
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.
|
||||
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)
|
||||
|
||||
ID = DiskLib.ogTypeToId ('CACHE', 'MSDOS')
|
||||
# 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)
|
||||
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)
|
||||
|
||||
# Actualiza la tabla de particiones en el kernel.
|
||||
DiskLib.ogUpdatePartitionTable()
|
||||
return True
|
||||
|
@ -139,15 +143,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]).returncode: ## if True, then sgdisk failed
|
||||
subprocess.run (['gdisk', disk], input='2\nw\nY\n', text=True)
|
||||
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)
|
||||
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']).returncode: ## if True, then parted failed
|
||||
subprocess.run (['fdisk', disk], input='w', text=True)
|
||||
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)
|
||||
# Eliminar la partición de caché.
|
||||
subprocess.run (['fdisk', disk], input=f'd\n{npart}\nw', text=True)
|
||||
subprocess.run (['fdisk', disk], input=f'd\n{npart}\nw', text=True, capture_output=True)
|
||||
# Borrar etiqueta de la caché.
|
||||
if os.path.exists ('/dev/disk/by-label/CACHE'):
|
||||
os.unlink ('/dev/disk/by-label/CACHE')
|
||||
|
@ -358,3 +362,46 @@ 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,6 +38,32 @@ 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.
|
||||
|
@ -61,12 +87,11 @@ def ogCreatePartitions (disk, parts):
|
|||
|
||||
PTTYPE = ogGetPartitionTableType (disk)
|
||||
if not PTTYPE: PTTYPE = 'MSDOS' # Por defecto para discos vacíos.
|
||||
|
||||
if 'GPT' == PTTYPE:
|
||||
return ogCreateGptPartitions (disk, parts)
|
||||
elif 'MSDOS' != PTTYPE:
|
||||
if PTTYPE not in ['MSDOS', 'GPT']:
|
||||
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)
|
||||
|
@ -78,24 +103,21 @@ 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).
|
||||
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:
|
||||
# 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
|
||||
|
||||
if 4096 == IOSIZE:
|
||||
START = 4096
|
||||
SECTORS -= 8192
|
||||
if CACHESIZE:
|
||||
SECTORS = SECTORS - CACHESIZE + 2048 - (SECTORS - CACHESIZE) % 2048 - 1
|
||||
else:
|
||||
START = 63
|
||||
else: ## 512
|
||||
if 'MSDOS' == PTTYPE: START = 63
|
||||
else: START = 2048
|
||||
if CACHESIZE:
|
||||
SECTORS -= CACHESIZE
|
||||
|
||||
|
@ -103,71 +125,108 @@ 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 de 512 B.
|
||||
SIZE *= 2
|
||||
|
||||
# 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 si la partición es extendida.
|
||||
EXTSTART = EXTSIZE = 0
|
||||
if 5 == ID:
|
||||
if PART > 4:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, '')
|
||||
if '5' == ID:
|
||||
if 'GPT' == PTTYPE:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, 'EXTENDED')
|
||||
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 not EXTSTART:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, '')
|
||||
return None
|
||||
START = EXTSTART
|
||||
SECTORS = EXTSTART+EXTSIZE
|
||||
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
|
||||
|
||||
# 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}, Id={ID}\n'
|
||||
sfdisk_input += f'{DISK}{NVME_PREFIX}{PART} : start={START}, size={SIZE}, type={ID}\n'
|
||||
|
||||
START += SIZE
|
||||
|
||||
# Error si se supera el nº total de sectores.
|
||||
if '4096' == IOSIZE and PART > 4:
|
||||
if 'MSDOS' == PTTYPE and 4096 == IOSIZE and PART > 4:
|
||||
START += 2048
|
||||
|
||||
# Error si se supera el nº total de sectores.
|
||||
if START > SECTORS:
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'{START//2} > {SECTORS//2}')
|
||||
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'partición "{TYPE}:{ORIG_SIZE}" no cabe')
|
||||
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}, Id=ca\n'
|
||||
sfdisk_input += f'{DISK}{NVME_PREFIX}{PART} : start={SECTORS+1}, size={CACHESIZE}, type={CACHE_ID}\n'
|
||||
else:
|
||||
sfdisk_input += f'{DISK}{NVME_PREFIX}{PART} : start=0, size=0, Id=0\n'
|
||||
sfdisk_input += f'{DISK}{NVME_PREFIX}{PART} : start=0, size=0, type=0\n'
|
||||
PART += 1
|
||||
|
||||
# Si se define partición extendida sin lógicas, crear particion 5 vacía.
|
||||
if 5 == PART and EXTSTART:
|
||||
sfdisk_input += f'{DISK}5 : start={EXTSTART}, SIZE={EXTSIZE}, Id=0\n'
|
||||
ID = ogTypeToId ('WINDOWS', PTTYPE)
|
||||
sfdisk_input += f'{DISK}5 : start={EXTSTART}, SIZE={EXTSIZE}, type={ID}\n'
|
||||
|
||||
# Desmontar los sistemas de archivos del disco antes de realizar las operaciones.
|
||||
FileSystemLib.ogUnmountAll (ND)
|
||||
|
@ -183,113 +242,6 @@ 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.
|
||||
|
@ -431,7 +383,7 @@ def ogDevToDisk(arg_dev):
|
|||
|
||||
def _getAllDisks():
|
||||
ret = []
|
||||
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()
|
||||
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()
|
||||
for line in all_disks:
|
||||
parts = line.split()
|
||||
if parts[5] == "disk":
|
||||
|
@ -785,9 +737,9 @@ def ogGetPartitionActive (disk):
|
|||
break
|
||||
|
||||
if lang is None:
|
||||
del os.environ['LANG']
|
||||
if 'LANG' in os.environ: del os.environ['LANG']
|
||||
else:
|
||||
os.environ['LAMG'] = lang
|
||||
os.environ['LANG'] = lang
|
||||
|
||||
return ret
|
||||
|
||||
|
@ -858,7 +810,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)
|
||||
|
@ -1277,6 +1229,23 @@ 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
|
@ -0,0 +1,345 @@
|
|||
#!/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()
|
|
@ -0,0 +1,121 @@
|
|||
|
||||
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')
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,544 @@
|
|||
|
||||
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"])
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
|
||||
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
|
|
@ -0,0 +1,111 @@
|
|||
|
||||
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)
|
|
@ -635,7 +635,7 @@ def ogGetImageInfo (imgfile):
|
|||
if lc_all is not None:
|
||||
os.environ["LC_ALL"] = lc_all
|
||||
else:
|
||||
del os.environ["LC_ALL"]
|
||||
if "LC_ALL" in os.environ: del os.environ["LC_ALL"]
|
||||
|
||||
if 'size' in partclone_info:
|
||||
tools = 'PARTCLONE'
|
||||
|
|
|
@ -0,0 +1,352 @@
|
|||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import glob
|
||||
import stat
|
||||
import shutil
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
import ogGlobals
|
||||
from InventoryLib import ogIsEfiActive
|
||||
from DiskLib import ogGetEsp
|
||||
from FileSystemLib import ogMount, ogUnmount
|
||||
|
||||
## sets envvar and writes to /etc/environment
|
||||
def env_export (k, v):
|
||||
os.environ[k] = str (v)
|
||||
already_present = False
|
||||
with open ('/etc/environment', 'r') as env_fd:
|
||||
for line in env_fd:
|
||||
if re.search (f'^{k}=', line):
|
||||
already_present = True
|
||||
break
|
||||
if not already_present:
|
||||
with open ('/etc/environment', 'a') as env_fd:
|
||||
env_fd.write (f'{k}={v}\n')
|
||||
return v
|
||||
|
||||
def loadenviron():
|
||||
# Idioma por defecto.
|
||||
LANG = os.environ.get ('LANG', 'es_ES')
|
||||
env_export ('LANG', 'es_ES')
|
||||
|
||||
# Directorios del proyecto OpenGnsys.
|
||||
OPENGNSYS = os.environ.get ('OPENGNSYS', '/opt/opengnsys')
|
||||
env_export ('OPENGNSYS', OPENGNSYS)
|
||||
|
||||
OGBIN = env_export ('OGBIN', f'{OPENGNSYS}/bin')
|
||||
OGETC = env_export ('OGETC', f'{OPENGNSYS}/etc')
|
||||
OGLIB = env_export ('OGLIB', f'{OPENGNSYS}/lib')
|
||||
OGAPI = env_export ('OGAPI', f'{OGLIB}/engine/bin')
|
||||
OGPYFUNCS = env_export ('OGPYFUNCS', f'{OPENGNSYS}/functions')
|
||||
OGSCRIPTS = env_export ('OGSCRIPTS', f'{OPENGNSYS}/scripts')
|
||||
OGIMG = env_export ('OGIMG', f'{OPENGNSYS}/images')
|
||||
OGCAC = env_export ('OGCAC', f'{OPENGNSYS}/cache')
|
||||
OGLOG = env_export ('OGLOG', f'{OPENGNSYS}/log')
|
||||
|
||||
# Exportar parámetros del kernel.
|
||||
with open ('/proc/cmdline', 'r') as fd: cmdline = fd.read()
|
||||
kvars = cmdline.split()
|
||||
for kvar in kvars:
|
||||
if '=' not in kvar: continue
|
||||
k, v = kvar.split ('=')
|
||||
env_export (k, v)
|
||||
|
||||
OGSERVERIMAGES = os.environ.get ('OGSERVERIMAGES', '')
|
||||
if 'ROOTREPO' not in os.environ or not os.environ.get ('ROOTREPO'):
|
||||
env_export ('ROOTREPO', OGSERVERIMAGES)
|
||||
|
||||
# Compatibilidad para usar proxy en clientes ogLive.
|
||||
http_proxy = os.environ.get ('http_proxy', '')
|
||||
ogproxy = os.environ.get ('ogproxy', '')
|
||||
if not http_proxy and ogproxy:
|
||||
env_export ('http_proxy', ogproxy)
|
||||
|
||||
def write_profile():
|
||||
## si estos accesos a os.environ fallan, es porque loadenviron() no se ejecutó
|
||||
OGSCRIPTS = os.environ['OGSCRIPTS']
|
||||
OGPYFUNCS = os.environ['OGPYFUNCS']
|
||||
OGBIN = os.environ['OGBIN']
|
||||
PYTHONPATH = os.environ['PYTHONPATH']
|
||||
LANG = os.environ['LANG']
|
||||
|
||||
PATH = os.environ.get ('PATH', '')
|
||||
|
||||
L = LANG[0:LANG.index('_')]
|
||||
with open ('/etc/profile.d/ogprofile.sh', 'w') as fd:
|
||||
fd.write (f'''
|
||||
(locale-gen {LANG} &>/dev/null &)
|
||||
export PATH={OGSCRIPTS}:{OGPYFUNCS}:{OGBIN}:{PATH}:/opt/oglive/rootfs/opt/drbl/sbin
|
||||
export PYTHONPATH={PYTHONPATH}
|
||||
sysctl -p &>/dev/null
|
||||
loadkeys {L} >/dev/null
|
||||
if [ ! -f /run/resolvconf/resolv.conf -a -n "$ogdns" ]; then
|
||||
mkdir -p /run/resolvconf
|
||||
echo "nameserver $ogdns" > /run/resolvconf/resolv.conf
|
||||
fi
|
||||
'''.strip() + '\n')
|
||||
|
||||
def clean_esp():
|
||||
## BootLib.bootOs() makes a copy of grub.cfg in /boot/grub within the ESP
|
||||
## clean it up
|
||||
if ogIsEfiActive():
|
||||
esp = ogGetEsp()
|
||||
if esp:
|
||||
esp_disk, esp_par = esp.split()
|
||||
mntpt = ogMount (esp_disk, esp_par)
|
||||
os.unlink (f'{mntpt}/boot/grub/grub.cfg')
|
||||
ogUnmount (esp_disk, esp_par)
|
||||
|
||||
def fileslinks():
|
||||
print (ogGlobals.lang.MSG_MAKELINKS)
|
||||
|
||||
# Shell BASH por defecto (para usar "runtest")
|
||||
if os.path.exists ('/bin/sh'): os.unlink ('/bin/sh')
|
||||
os.symlink ('/bin/bash', '/bin/sh')
|
||||
|
||||
# Crear directorio de bloqueos
|
||||
## for some reason we need try/catch even when using 'exist_ok=True'
|
||||
try: os.makedirs ('/var/lock', exist_ok=True)
|
||||
except FileExistsError: pass
|
||||
try: os.makedirs ('/run/lock', exist_ok=True)
|
||||
except FileExistsError: pass
|
||||
|
||||
# Crear ficheros temporales.
|
||||
for f in [ogGlobals.OGLOGCOMMAND, ogGlobals.OGLOGCOMMAND + '.tmp', ogGlobals.OGLOGSESSION, '/tmp/menu.tmp']:
|
||||
open (f, 'w').close()
|
||||
os.chmod (f, 0o777)
|
||||
|
||||
# Enlaces para Qt Embeded.
|
||||
# son cosas de QT4, ya no aplica
|
||||
|
||||
# Autenticación con clave pública para SSH
|
||||
if os.path.exists ('/scripts/ssl/authorized_keys'):
|
||||
for f in glob.glob ('/scripts/ssl/*'):
|
||||
shutil.copy2 (f, '/root/.ssh/')
|
||||
|
||||
def loadmodules():
|
||||
print (ogGlobals.lang.MSG_LOADMODULES)
|
||||
|
||||
# Módulo del ratón.
|
||||
subprocess.run (['modprobe', 'psmouse'], stderr=subprocess.DEVNULL)
|
||||
|
||||
# Cargar módulos específicos del kernel del cliente.
|
||||
uname_r = os.uname()[2]
|
||||
for m in glob.glob (f'{ogGlobals.OGLIB}/modules/{uname_r}/*.ko'):
|
||||
subprocess.run (['insmod', m], capture_output=True)
|
||||
|
||||
def metadevs():
|
||||
print (ogGlobals.lang.MSG_DETECTLVMRAID)
|
||||
subprocess.run (['vgchange', '-ay'], capture_output=True) # Detectar metadispositivos LVM.
|
||||
subprocess.run (['dmraid', '-ay'], capture_output=True) # Detectar metadispositivos RAID.
|
||||
|
||||
def mountrepo():
|
||||
## si estos accesos a os.environ fallan, es porque loadenviron() no se ejecutó
|
||||
ROOTREPO = os.environ['ROOTREPO']
|
||||
|
||||
ROOTSERVER = os.environ.get ('ROOTSERVER', '')
|
||||
ogactiveadmin = os.environ.get ('ogactiveadmin', '')
|
||||
ogprotocol = os.environ.get ('ogprotocol', '')
|
||||
ogstatus = os.environ.get ('ogstatus', '')
|
||||
SERVER = os.environ.get ('SERVER', '')
|
||||
if not ROOTREPO: ROOTREPO = ROOTSERVER
|
||||
|
||||
# TODO Revisar proceso de arranque para no montar 2 veces el repositorio.
|
||||
if 'true' == ogactiveadmin:
|
||||
os.environ['boot'] = 'admin' # ATENCIÓN: siempre en modo "admin".
|
||||
subprocess.run (['umount', ogGlobals.OGIMG], stderr=subprocess.DEVNULL)
|
||||
|
||||
if 'nfs' == ogprotocol:
|
||||
subprocess.run (['mount.nfs', f'{ROOTREPO}:{ogGlobals.OGIMG}', ogGlobals.OGIMG, '-o', 'rw,nolock'])
|
||||
|
||||
elif 'smb' == ogprotocol:
|
||||
PASS = subprocess.run ('grep "^[ \t]*\\(export \\)\\?OPTIONS=" /scripts/ogfunctions 2>&1 | sed "s/\\(.*\\)pass=\\(\\w*\\)\\(.*\\)/\\2/"', shell=True, capture_output=True, text=True).stdout.strip()
|
||||
if not PASS: PASS = 'og'
|
||||
subprocess.run (['mount.cifs', f'//{ROOTREPO}/ogimages', ogGlobals.OGIMG, '-o', f'rw,serverino,acl,username=opengnsys,password={PASS}'])
|
||||
|
||||
elif 'local' == ogprotocol: # TODO: hacer funcion dentro de este script que monte smb
|
||||
# Comprobamos que estatus sea online.
|
||||
if 'offline' == ogstatus or '' == SERVER:
|
||||
# Si estatus es offline buscamos un dispositivo con etiqueta repo
|
||||
# y si no existe montamos la cache como repo (si existe).
|
||||
TYPE = subprocess.run ('blkid | grep REPO | awk -F"TYPE=" \'{print $2}\' | tr -d \\"', shell=True, capture_output=True, text=True).stdout.strip()
|
||||
if '' == TYPE:
|
||||
cac_img = f'{ogGlobals.OGCAC}/{ogGlobals.OGIMG}'
|
||||
if os.path.isdir (cac_img):
|
||||
subprocess.run (['mount', '--bind', cac_img, ogGlobals.OGIMG])
|
||||
else:
|
||||
subprocess.run (['mount', '-t', TYPE, 'LABEL=REPO', ogGlobals.OGIMG])
|
||||
else:
|
||||
# Comprobamos que existe un servicio de samba.
|
||||
rc = subprocess.run (['smbclient', '-L', SERVER, '-N'], capture_output=True, text=True).returncode
|
||||
if not rc: ## success
|
||||
PASS = subprocess.run ('grep "^[ \t]*\\(export \\)\\?OPTIONS=" /scripts/ogfunctions 2>&1 | sed "s/\\(.*\\)pass=\\(\\w*\\)\\(.*\\)/\\2/"', shell=True, capture_output=True, text=True).stdout.strip()
|
||||
if not PASS: PASS = 'og'
|
||||
subprocess.run (['mount.cifs', f'//{ROOTREPO}/ogimages', ogGlobals.OGIMG, '-o', f'rw,serverino,acl,username=opengnsys,password={PASS}'])
|
||||
|
||||
def poweroff():
|
||||
ogntp = os.environ.get ('ogntp', '')
|
||||
status = os.environ.get ('status', '')
|
||||
|
||||
print (ogGlobals.lang.MSG_POWEROFFCONF)
|
||||
# Sincronización horaria con servidor NTP.
|
||||
if ogntp and 'offline' != status:
|
||||
subprocess.run (['ntpdate', ogntp])
|
||||
|
||||
# Crear fichero de configuración por defecto (30 min. de espera).
|
||||
POWEROFFCONF = '/etc/poweroff.conf'
|
||||
with open (POWEROFFCONF, 'w') as fd:
|
||||
fd.write (f'''
|
||||
POWEROFFSLEEP=30
|
||||
POWEROFFTIME=
|
||||
'''.strip() + '\n')
|
||||
# Incluir zona horaria en el fichero de configuración.
|
||||
awk_out = subprocess.run (['awk', 'BEGIN {RS=" "} /^TZ=/ {print}', '/proc/cmdline'], capture_output=True, text=True).stdout.strip()
|
||||
with open (POWEROFFCONF, 'a') as fd:
|
||||
fd.write (awk_out + '\n')
|
||||
|
||||
# Lanzar el proceso "cron".
|
||||
subprocess.run (['cron', '-l'])
|
||||
|
||||
# Definir la "crontab" lanzando el proceso de comprobación cada minuto.
|
||||
crontab_entry = f'* * * * * [ -x {ogGlobals.OGBIN}/poweroffconf ] && {ogGlobals.OGBIN}/poweroffconf\n'
|
||||
subprocess.run (['crontab', '-'], input=crontab_entry, text=True)
|
||||
|
||||
def filebeat():
|
||||
oglog = os.environ.get ('oglog', '')
|
||||
F = '/etc/filebeat/filebeat.yml'
|
||||
OPENSEARCH_PORT = '9200'
|
||||
|
||||
if not os.path.exists (F): return
|
||||
|
||||
PASS = subprocess.run ('grep "^[ \t]*\\(export \\)\\?OPTIONS=" /scripts/ogfunctions 2>&1 | sed "s/\\(.*\\)pass=\\(\\w*\\)\\(.*\\)/\\2/"', shell=True, capture_output=True, text=True).stdout.strip() ## taken from a sibling script
|
||||
if not PASS: PASS = 'og'
|
||||
ogkdf = subprocess.run (f'echo -n {PASS} |sha256sum |cut -c1-12', shell=True, capture_output=True, text=True).stdout.strip()
|
||||
PASS = 'OG+' + ogkdf
|
||||
|
||||
os.chmod (F, 0o600)
|
||||
subprocess.run (['sed', '-i',
|
||||
'-e', f's/__OGLOG_IP/{oglog}/g',
|
||||
'-e', f's/__OGLOG_PORT__/{OPENSEARCH_PORT}/g',
|
||||
'-e', f's/__OPENSEARCH_PASSWORD__/{PASS}/g',
|
||||
F
|
||||
])
|
||||
|
||||
os.makedirs ('/var/log/filebeat', exist_ok=True)
|
||||
subprocess.Popen (['/usr/bin/filebeat', '-c', F, '--path.home', '/usr/share/filebeat', '--path.config', '/etc/filebeat', '--path.data', '/var/lib/filebeat', '--path.logs', '/var/log/filebeat'])
|
||||
|
||||
def stunnel():
|
||||
ogcore = os.environ.get ('ogcore', '')
|
||||
ogusetls = os.environ.get ('ogusetls', '')
|
||||
ogverifytls = os.environ.get ('ogverifytls', '')
|
||||
|
||||
with open ('/etc/stunnel/menu.conf', 'w') as fd: fd.write (f'''
|
||||
setuid = stunnel4
|
||||
setgid = stunnel4
|
||||
pid = /var/run/stunnel4/menu.pid
|
||||
foreground = yes
|
||||
debug = info
|
||||
|
||||
[menu]
|
||||
client = yes
|
||||
accept = 127.0.0.1:81
|
||||
connect = {ogcore}:8443
|
||||
'''.strip() + '\n')
|
||||
if 'true' == ogusetls:
|
||||
if 'true' == ogverifytls:
|
||||
## use tls and verify
|
||||
with open ('/etc/stunnel/menu.conf', 'a') as fd: fd.write (f'''
|
||||
cert = /opt/opengnsys/etc/ogagent.crt
|
||||
key = /opt/opengnsys/etc/ogagent.key
|
||||
CAfile = /opt/opengnsys/etc/ca.crt
|
||||
requireCert = yes
|
||||
verifyChain = yes
|
||||
'''.strip() + '\n')
|
||||
else:
|
||||
## use tls but not verify
|
||||
with open ('/etc/stunnel/menu.conf', 'a') as fd: fd.write (f'''
|
||||
cert = /opt/opengnsys/etc/ogagent.crt
|
||||
key = /opt/opengnsys/etc/ogagent.key
|
||||
CAfile = /opt/opengnsys/etc/ca.crt
|
||||
requireCert = no
|
||||
verifyChain = no
|
||||
'''.strip() + '\n')
|
||||
else:
|
||||
## don't use tls
|
||||
with open ('/etc/stunnel/menu.conf', 'a') as fd: fd.write (f'''
|
||||
requireCert = no
|
||||
verifyChain = no
|
||||
'''.strip() + '\n')
|
||||
|
||||
os.makedirs ('/var/run/stunnel4', exist_ok=True)
|
||||
shutil.chown ('/var/run/stunnel4', 'stunnel4', 'stunnel4')
|
||||
with open ('/var/log/stunnel4/menu.log', 'a') as stunnel_log_fd:
|
||||
subprocess.Popen (['stunnel', '/etc/stunnel/menu.conf'], stdout=stunnel_log_fd, stderr=subprocess.STDOUT)
|
||||
|
||||
def dbus():
|
||||
if os.path.exists ('/etc/dbus-1/system.d/ogbrowser.conf'):
|
||||
os.makedirs ('/run/dbus', exist_ok=True)
|
||||
dbus_addr = subprocess.run (['dbus-daemon', '--print-address', '--system', '--nosyslog'], capture_output=True, text=True).stdout.strip()
|
||||
env_export ('DBUS_SESSION_BUS_ADDRESS', dbus_addr)
|
||||
with open ('/var/log/dbus-monitor.log', 'w') as dbus_mon_fd:
|
||||
subprocess.Popen (['dbus-monitor', '--system'], stdout=dbus_mon_fd, stderr=subprocess.STDOUT)
|
||||
|
||||
def otherservices():
|
||||
DEVICE = os.environ.get ('DEVICE', '')
|
||||
|
||||
if ogIsEfiActive():
|
||||
subprocess.run (['mount', '-t', 'efivarfs', 'none', '/sys/firmware/efi/efivars'])
|
||||
|
||||
print (ogGlobals.lang.MSG_OTHERSERVICES)
|
||||
|
||||
if os.path.exists ('/dev/log') and not stat.S_ISSOCK (os.stat ('/dev/log').st_mode):
|
||||
subprocess.run (['service', 'rsyslog', 'start'])
|
||||
|
||||
# root password
|
||||
PASS = subprocess.run ('grep "^[ \t]*\\(export \\)\\?OPTIONS=" /scripts/ogfunctions 2>&1 | sed "s/\\(.*\\)pass=\\(\\w*\\)\\(.*\\)/\\2/"', shell=True, capture_output=True, text=True).stdout.strip()
|
||||
if not PASS: PASS = 'og'
|
||||
subprocess.run (['passwd', 'root'], input=f'{PASS}\n{PASS}\n', stderr=subprocess.DEVNULL, text=True)
|
||||
|
||||
subprocess.run (['/etc/init.d/ssh', 'start'], capture_output=True, text=True)
|
||||
|
||||
#setterm -blank 0 -powersave off -powerdown 0 < /dev/console > /dev/console 2>&1 ## apagado de monitor
|
||||
subprocess.run (['ethtool', '-s', DEVICE, 'wol', 'g'], stderr=subprocess.DEVNULL) ## Activado WOL en la interfaz usada en arranque PXE.
|
||||
|
||||
def runhttplog():
|
||||
## si estos accesos a os.environ fallan, es porque loadenviron() no se ejecutó
|
||||
OPENGNSYS = os.environ['OPENGNSYS']
|
||||
|
||||
try:
|
||||
shutil.copy2 ('/etc/lighttpd/lighttpd.conf', '/etc/lighttpd/lighttpd.conf.back')
|
||||
shutil.copy2 ('/etc/lighttpd/conf-enabled/10-cgi.conf', '/etc/lighttpd/conf-enabled/10-cgi.conf.back')
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
shutil.copy2 (f'{OPENGNSYS}/lib/httpd/lighttpd.conf', '/etc/lighttpd/')
|
||||
shutil.copy2 (f'{OPENGNSYS}/lib/httpd/10-cgi.conf', '/etc/lighttpd/conf-enabled/')
|
||||
|
||||
subprocess.run (['/etc/init.d/lighttpd', 'start'], capture_output=True)
|
||||
|
||||
o = OPENGNSYS
|
||||
while '/' != o:
|
||||
os.chmod (o, 0o755)
|
||||
o = os.path.dirname (o)
|
||||
os.makedirs ('/usr/lib/cgi-bin', exist_ok=True)
|
||||
|
||||
for filename in os.listdir (f'{OPENGNSYS}/lib/httpd/'):
|
||||
full_file_name = os.path.join (f'{OPENGNSYS}/lib/httpd/', filename)
|
||||
if os.path.isfile (full_file_name):
|
||||
shutil.copy2 (full_file_name, '/usr/lib/cgi-bin')
|
||||
|
||||
## dstat fails because /var/lib/pcp/pmns/root does not exist.
|
||||
## we work around that by starting/stopping pmcd once. When it starts, it creates the missing file.
|
||||
if not os.path.exists ('/var/lib/pcp/pmns/root'):
|
||||
subprocess.run (['/etc/init.d/pmcd', 'start'], capture_output=True)
|
||||
subprocess.run (['/etc/init.d/pmcd', 'stop'], capture_output=True)
|
||||
|
||||
with open ('/tmp/bandwidth', 'w') as f:
|
||||
subprocess.Popen (['dstat', '-dn', '10'], stdout=f)
|
||||
|
||||
with open (ogGlobals.OGLOGSESSION, 'a') as fd:
|
||||
fd.write ('WAITING\n')
|
|
@ -255,7 +255,7 @@ def ogGetRepoIp():
|
|||
#@note Comprobacion segun protocolo de conexion al Repo
|
||||
#*/ ##
|
||||
def ogGetServerIp():
|
||||
return os.environ['ogcore']
|
||||
return os.environ.get ('ogcore', '')
|
||||
|
||||
#/**
|
||||
# ogGetServerPort
|
||||
|
@ -263,10 +263,7 @@ def ogGetServerIp():
|
|||
#@return str_port - Puerto
|
||||
#*/ ##
|
||||
def ogGetServerPort():
|
||||
if 'ogcore_port' in os.environ:
|
||||
return os.environ['ogcore_port']
|
||||
else:
|
||||
return '8443'
|
||||
return os.environ.get ('ogcore_port', '8443')
|
||||
|
||||
|
||||
#/**
|
||||
|
|
|
@ -224,7 +224,6 @@ 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
|
||||
|
@ -483,7 +482,6 @@ 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
|
||||
|
|
|
@ -178,7 +178,7 @@ def ogGetCaller():
|
|||
caller = words[0].lstrip("-")
|
||||
|
||||
if cols is None:
|
||||
del (os.environ['COLUMNS'])
|
||||
if 'COLUMNS' in os.environ: del os.environ['COLUMNS']
|
||||
else:
|
||||
os.environ['COLUMNS'] = cols
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ MCASTWAIT=30 # timeout (segundos) para abortar la la tran
|
|||
#FACTORSYNC=120 # Factor de compresion para las imagenes (windos en ext4).
|
||||
#BACKUP=False # Realizar copia de seguridad antes de crear la imagen.
|
||||
#IMGFS='EXT4' # Sistema de archivo de la imagenes sincronizadas. EXT4 o BTRFS
|
||||
#OGSLEEP=20 # Tiempo de sleep antes de realizar el reboot
|
||||
OGSLEEP=4 # Tiempo de sleep antes de realizar el reboot
|
||||
NODEBUGFUNCTIONS=['ogCreateImageSyntax', 'ogGetHivePath', 'ogGetOsType', 'ogRestoreImageSyntax', 'ogUnmountAll', 'ogUnmountCache'] # Funciones que no deben mostrar salida de avisos si son llamadas por otras funciones.
|
||||
#DEFAULTSPEED=''
|
||||
## /engine.cfg
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
bootOs
|
|
@ -1 +0,0 @@
|
|||
bootOs
|
|
@ -50,6 +50,8 @@ 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()
|
||||
|
|
|
@ -1,39 +1,74 @@
|
|||
#!/bin/bash
|
||||
# Scirpt de ejemplo para apagar un ordenador
|
||||
# Nota: se usa como base para el programa de apagado de OpenGnsys Admin.
|
||||
#!/usr/bin/python3
|
||||
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import time
|
||||
import subprocess
|
||||
|
||||
# Registrar ejecución manual de script.
|
||||
case "$(ogGetCaller)" in
|
||||
browser|bash) ogEcho log info "Script: $0" ;;
|
||||
esac
|
||||
import ogGlobals
|
||||
from SystemLib import ogGetCaller, ogEcho
|
||||
from DiskLib import ogDiskToDev
|
||||
from FileSystemLib import ogUnmountAll
|
||||
from CacheLib import ogUnmountCache
|
||||
|
||||
DEVICE = os.environ.get ('DEVICE', '')
|
||||
ogstatus = os.environ.get ('ogstatus', '')
|
||||
|
||||
PROG = os.path.basename (sys.argv[0])
|
||||
is_reboot = 'reboot'==PROG
|
||||
|
||||
TIME = None
|
||||
try:
|
||||
TIME = int (sys.argv[1])
|
||||
except:
|
||||
pass
|
||||
|
||||
# Registrar ejecución manual de script.
|
||||
c = ogGetCaller()
|
||||
if c in ['browser', 'OGBrowser', 'bash']:
|
||||
ogEcho ('log', 'info', f'Script: {PROG}')
|
||||
|
||||
# Cargamos el valor por defecto del tiempo de sleep
|
||||
if TIME:
|
||||
print (f'[5] Se ha introducido un retardo de {TIME} segundos para reiniciar')
|
||||
else:
|
||||
TIME = ogGlobals.OGSLEEP
|
||||
print (f'[5] No se ha introducido un retardo, {TIME} segundos para reiniciar')
|
||||
|
||||
# No registrar errores.
|
||||
export DEBUG="no"
|
||||
#DEBUG=no
|
||||
|
||||
# Desmontar los sistemas de archivos y la caché local.
|
||||
echo "[10] Desmontar todos los sistemas de archivos."
|
||||
sync
|
||||
for (( i=1; i <= $(ogDiskToDev | wc -w); i++ )); do
|
||||
ogUnmountAll $i &>/dev/null
|
||||
done
|
||||
echo "[50] Desmontar cache local."
|
||||
ogUnmountCache &>/dev/null
|
||||
print ('[10] Desmontar todos los sistemas de archivos.')
|
||||
subprocess.run (['sync'])
|
||||
ndisks = len (ogDiskToDev())
|
||||
for d in range (1, ndisks+1):
|
||||
ogUnmountAll (d)
|
||||
print ('[50] Desmontar cache local.')
|
||||
ogUnmountCache()
|
||||
|
||||
# Volver a registrar errores.
|
||||
unset DEBUG
|
||||
#DEBUG=yes
|
||||
|
||||
echo "[70] Apagando el equipo."
|
||||
if is_reboot:
|
||||
print ('[90] Reiniciar el equipo.')
|
||||
else:
|
||||
print ('[70] Apagando el equipo.')
|
||||
# Estado correcto de Wake-On-Lan antes de apagar.
|
||||
ethtool -s $DEVICE wol g 2>/dev/null
|
||||
subprocess.run (['ethtool', '-s', DEVICE, 'wol', 'g'], stderr=subprocess.DEVNULL)
|
||||
# Detectar Busybox.
|
||||
BUSYBOX=$(which busyboxOLD)
|
||||
BUSYBOX=${BUSYBOX:-"busybox"}
|
||||
BUSYBOX = shutil.which ('busyboxOLD')
|
||||
if not BUSYBOX: BUSYBOX = shutil.which ('busybox')
|
||||
|
||||
# Retardo para dar lugar al registro en cola de acciones.
|
||||
sleep 5
|
||||
time.sleep (TIME)
|
||||
# Parar Browser para evitar "cuelgues".
|
||||
[ "$ogstatus" == "offline" ] || pkill browser
|
||||
if 'offline' != ogstatus:
|
||||
subprocess.run (['killall', 'QtWebEngineProcess', 'OGBrowser', 'i3', 'sway', 'Xorg', 'startx'], stderr=subprocess.DEVNULL)
|
||||
# Apagar.
|
||||
$BUSYBOX poweroff
|
||||
|
||||
if is_reboot:
|
||||
subprocess.run ([BUSYBOX, 'reboot'])
|
||||
else:
|
||||
subprocess.run ([BUSYBOX, 'poweroff'])
|
||||
|
|
|
@ -1,54 +0,0 @@
|
|||
#!/bin/bash
|
||||
# Script de ejemplo para reiniciar un ordenador
|
||||
# Nota: se usa como base para el programa de reinicio de OpenGnsys Admin.
|
||||
|
||||
|
||||
# Registrar ejecución manual de script.
|
||||
case "$(ogGetCaller)" in
|
||||
browser|bash) ogEcho log info "Script: $0" ;;
|
||||
esac
|
||||
|
||||
# Cargamos el valor por defecto del tiempo de sleep
|
||||
[ -z $OGSLEEP ] && source /opt/opengnsys/etc/engine.cfg
|
||||
|
||||
# Si se recibe un parametro sera el tiempo de sleep antes de realizar el reboot
|
||||
if [ $# == 1 ] && [ "${1//[^0-9]/}" == "$1" ]
|
||||
then
|
||||
TIME=$1
|
||||
echo "[5] Se ha introducido un retardo de $TIME segundos para reiniciar"
|
||||
else
|
||||
# Sin parámetros, o el parámetro introducido no es un número
|
||||
TIME=${OGSLEEP:-5}
|
||||
echo "[5] No se ha introducido un retardo, $TIME segundos para reiniciar"
|
||||
fi
|
||||
|
||||
# No registrar errores.
|
||||
export DEBUG="no"
|
||||
|
||||
# Desmontar los sistemas de archivos y la caché local.
|
||||
echo "[10] Desmontar todos los sistemas de archivos."
|
||||
sync
|
||||
for (( i=1; i <= $(ogDiskToDev | wc -w); i++ )); do
|
||||
ogUnmountAll $i &>/dev/null
|
||||
done
|
||||
echo "[50] Desmontar cache local."
|
||||
ogUnmountCache &>/dev/null
|
||||
|
||||
# Volver a registrar errores.
|
||||
unset DEBUG
|
||||
|
||||
echo "[90] Reiniciar el equipo."
|
||||
# Estado correcto de Wake-On-Lan antes de reiniciar.
|
||||
ethtool -s $DEVICE wol g 2>/dev/null
|
||||
# Detectar Busybox.
|
||||
BUSYBOX=$(which busyboxOLD)
|
||||
BUSYBOX=${BUSYBOX:-"busybox"}
|
||||
|
||||
# Retardo para dar lugar al registro en cola de acciones.
|
||||
sleep $TIME
|
||||
# Parar Browser para evitar "cuelgues".
|
||||
[ "$ogstatus" == "offline" ] || pkill browser
|
||||
# Reiniciar.
|
||||
$BUSYBOX reboot
|
||||
|
||||
|
|
@ -0,0 +1 @@
|
|||
poweroff
|
|
@ -1,38 +0,0 @@
|
|||
import shutil
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
def main():
|
||||
# Copy lighttpd.conf
|
||||
shutil.copy('/etc/lighttpd/lighttpd.conf', '/etc/lighttpd/lighttpd.conf.back')
|
||||
shutil.copy('/opt/opengnsys/lib/httpd/lighttpd.conf', '/etc/lighttpd/')
|
||||
|
||||
# Copy 10-cgi.conf
|
||||
shutil.copy('/etc/lighttpd/conf-enabled/10-cgi.conf', '/etc/lighttpd/conf-enabled/10-cgi.conf.back')
|
||||
shutil.copy('/opt/opengnsys/lib/httpd/10-cgi.conf', '/etc/lighttpd/conf-enabled/')
|
||||
|
||||
# Start lighttpd service
|
||||
subprocess.run(['/etc/init.d/lighttpd', 'start'])
|
||||
|
||||
# Change permissions and create directories
|
||||
os.chmod('/opt', 0o755)
|
||||
os.makedirs('/usr/lib/cgi-bin', exist_ok=True)
|
||||
|
||||
# Copy files to /usr/lib/cgi-bin
|
||||
for filename in os.listdir('/opt/opengnsys/lib/httpd/'):
|
||||
full_file_name = os.path.join('/opt/opengnsys/lib/httpd/', filename)
|
||||
if os.path.isfile(full_file_name):
|
||||
shutil.copy(full_file_name, '/usr/lib/cgi-bin')
|
||||
|
||||
# Run dstat command
|
||||
with open('/tmp/bandwidth', 'w') as f:
|
||||
subprocess.Popen(['dstat', '-dn', '10'], stdout=f)
|
||||
|
||||
# Append "WAITING" to OGLOGSESSION
|
||||
oglogsession = os.getenv('OGLOGSESSION')
|
||||
if oglogsession:
|
||||
with open(oglogsession, 'a') as f:
|
||||
f.write("WAITING\n")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
Loading…
Reference in New Issue