From 4342a5c27e0663b2ddf3afb64d34d65d92767b32 Mon Sep 17 00:00:00 2001 From: Natalia Serrano Date: Mon, 11 Nov 2024 16:28:03 +0100 Subject: [PATCH] refs #1101 add ogGetPath() and dependencies --- client/lib/engine/bin/CacheLib.py | 34 ++-- client/lib/engine/bin/FileLib.py | 122 +++++++----- client/lib/engine/bin/FileSystemLib.py | 250 ++++++++++++++----------- client/lib/engine/bin/ogGlobals.py | 25 ++- 4 files changed, 244 insertions(+), 187 deletions(-) diff --git a/client/lib/engine/bin/CacheLib.py b/client/lib/engine/bin/CacheLib.py index 13913c5..a813607 100755 --- a/client/lib/engine/bin/CacheLib.py +++ b/client/lib/engine/bin/CacheLib.py @@ -5,9 +5,11 @@ import shutil import sys import platform +import ogGlobals +import SystemLib import DiskLib - -print (">>>>>>>>>>>>>>>>>>>> Load ", __name__, " <<<<<<<<<<<<<<<<<<<<<<") +import FileSystemLib +import CacheLib def ogCreateCache(ndisk=1, npart=4, partsize=None): """ @@ -193,21 +195,21 @@ def ogGetCacheSpace(): return free_space_kb + +#/** +# ogMountCache +#@brief Monta la partición Cache y exporta la variable $OGCAC +#@param sin parametros +#@return path_mountpoint - Punto de montaje del sistema de archivos de cache. +#@warning Salidas de errores no determinada +#*/ ## def ogMountCache(): - """ - Monta la partición de caché en el directorio /mnt/sda4. - - :raises RuntimeError: Si ocurre un error durante el montaje de la partición de caché. - """ - # Si se solicita, mostrar ayuda. - if len(sys.argv) > 1 and sys.argv[1] == "help": - ogHelp("ogMountCache", "help", "ogMountCache") - - # Montar la partición de caché en /mnt/sda4. - try: - subprocess.run(["mount", ogFindCache(), "/mnt/sda4"], check=True) - except subprocess.CalledProcessError as e: - raise RuntimeError(f"Error al montar la partición de caché: {e}") + c = CacheLib.ogFindCache().split() + m = FileSystemLib.ogMountFs (c[0], c[1]) + if not m: + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, ogGlobals.lang.MSG_NOCACHE) + #return + return m def ogUnmountCache(): """ diff --git a/client/lib/engine/bin/FileLib.py b/client/lib/engine/bin/FileLib.py index 868e4eb..89a24d4 100755 --- a/client/lib/engine/bin/FileLib.py +++ b/client/lib/engine/bin/FileLib.py @@ -1,6 +1,8 @@ import subprocess import os import shutil + +import ogGlobals import SystemLib import CacheLib import FileSystemLib @@ -146,66 +148,82 @@ def ogDeleteTree(*args): except OSError as e: SystemLib.ogRaiseError(OG_ERR_NOTFOUND, *args) return - -def ogGetPath(*args): - # Variables locales. - MNTDIR = None - FILE = None - PREVFILE = None - FILEPATH = None - CURRENTDIR = None - # Si se solicita, mostrar ayuda. - if "help" in args: - SystemLib.ogHelp("$FUNCNAME", "$FUNCNAME [ str_repo | int_ndisk int_npartition ] path_filepath", "$FUNCNAME \"/mnt/sda1/windows/system32\" ==> /mnt/sda1/WINDOWS/System32", "$FUNCNAME REPO /etc/fstab ==> /opt/opengnsys/images/etc/fstab", "$FUNCNAME 1 1 \"/windows/system32\" ==> /mnt/sda1/WINDOWS/System32") - return - # Procesar camino según el número de parámetros. - if len(args) == 1: - FILE = args[0] - elif len(args) == 2: - if args[0].upper() == "REPO": - FILE = os.path.join(OGIMG, args[1]) - elif args[0].upper() == "CACHE": - MNTDIR = CacheLib.ogMountCache() - if not MNTDIR: - return - FILE = os.path.join(MNTDIR, OGIMG, args[1]) - elif args[0].upper() == "CDROM": - MNTDIR = FileSystemLib.ogMountCdrom() - if not MNTDIR: - return - FILE = os.path.join(MNTDIR, args[1]) +#/** +# ogGetPath [ str_repo | int_ndisk int_npartition ] path_filepath +#@brief Inicia el proceso de arranque de un sistema de archivos. +#@param path_filepath camino del fichero (independiente de mayúsculas) +#@param str_repo repositorio de ficheros +#@param int_ndisk nº de orden del disco +#@param int_npartition nº de orden de la partición +#@return path_file - camino completo real del fichero. +#@note repo = { REPO, CACHE, CDROM } +#@note Requisitos: \c grep \c sed +#@exception OG_ERR_FORMAT Formato incorrecto. +#@exception OG_ERR_NOTFOUND Fichero o dispositivo no encontrado. +#@exception OG_ERR_PARTITION Tipo de partición desconocido o no se puede montar. +#@warning En caso de error, sólo devuelve el código y no da mensajes. +#@todo Terminar de definir parámetros para acceso a repositorios. +#*/ ## +#ogGetPath (file='/mnt/sda1/windows/system32') ==> '/mnt/sda1/WINDOWS/System32' +#ogGetPath (src='REPO', file='/etc/fstab') ==> '/opt/opengnsys/images/etc/fstab' +#ogGetPath (src='1 1', file='/windows/system32') ==> '/mnt/sda1/WINDOWS/System32' +def ogGetPath (src=None, file=None): + if file is None: + raise TypeError ('missing required argument: "file"') + + f = file + if src is not None: + if 'REPO' == src: + f = os.path.join (ogGlobals.OGIMG, file.strip('/')) + elif 'CACHE' == src: + mntdir = CacheLib.ogMountCache() + if not mntdir: return None + f = os.path.join (mntdir, ogGlobals.OGIMG.strip('/'), file.strip('/')) + elif 'CDROM' == src: + mntdir = FileSystemLib.ogMountCdrom() + if not mntdir: return None + f = os.path.join (mntdir, file.strip('/')) else: - SystemLib.ogRaiseError(OG_ERR_FORMAT) - return - elif len(args) == 3: - MNTDIR = FileSystemLib.ogMount(args[0], args[1]) - if not MNTDIR: - return - FILE = os.path.join(MNTDIR, args[2]) - else: - SystemLib.ogRaiseError(OG_ERR_FORMAT) - return + try: + disk, part = src.split() + except ValueError: + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, '') + return + mntdir = FileSystemLib.ogMount (disk, part) + if not mntdir: return None + f = os.path.join (mntdir, file.strip('/')) - # Eliminar caracteres \c / duplicados y finales. - FILE = os.path.normpath(FILE) + f = os.path.normpath (f) - # Comprobar si existe el fichero para reducir tiempos. - if os.path.exists(FILE): - FILEPATH = FILE + if os.path.exists (f): + filepath = f + #print (f'f ({f}) existe, filepath=f ({filepath})') else: # Buscar el nombre correcto en cada subdirectorio del camino. - FILEPATH = "/" - while FILE != PREVFILE: - FILEPATH = os.path.join(FILEPATH.rstrip("/"), FILE.split("/")[0]) - PREVFILE = FILE - FILE = "/".join(FILE.split("/")[1:]) + prevfile = '' + filepath = '/' + #print (f'f ({f}) prevfile ({prevfile})') + while f != prevfile: + #print ('\nno son iguales, nueva iteracion...') + f_first_component = f.split ('/')[0] ## take 1st component + ls_path = os.path.join (filepath, f_first_component) ## "ls" makes reference to the original bash version + #print (f'f_first_component ({f_first_component}) ls_path ({ls_path})') - if FILEPATH: - return FILEPATH - else: - return None + ## build filepath to return + if os.path.exists (ls_path): + filepath = ls_path + #print (f'ls_path existe, filepath ({filepath})') + else: + filepath = subprocess.run (['find', filepath, '-maxdepth', '1', '-iname', f_first_component, '-print'], capture_output=True, text=True).stdout.strip() + #print (f'ls_path no existe, filepath ({filepath})') + + prevfile = f + f = '/'.join (f.split('/')[1:]) ## remove 1st component + #print (f'f ({f}) prevfile ({prevfile})') + + return filepath def ogGetParentPath(*args): # Variables locales. diff --git a/client/lib/engine/bin/FileSystemLib.py b/client/lib/engine/bin/FileSystemLib.py index 72914af..e99fd31 100755 --- a/client/lib/engine/bin/FileSystemLib.py +++ b/client/lib/engine/bin/FileSystemLib.py @@ -1,13 +1,12 @@ import subprocess import sys +import os.path import ogGlobals import SystemLib import DiskLib import CacheLib -print (">>>>>>>>>>>>>>>>>>>> Load ", __name__, " <<<<<<<<<<<<<<<<<<<<<<") - def ogCheckFs(int_ndisk, int_nfilesys): # Si se solicita, mostrar ayuda. if int_ndisk == "help": @@ -398,25 +397,24 @@ def ogGetFsType(disk, part): return TYPE -def ogGetMountPoint(int_ndisk, int_nfilesys): - # Si se solicita, mostrar ayuda. - if len(sys.argv) == 3 and sys.argv[2] == "help": - ogHelp("ogGetMountPoint", "ogGetMountPoint int_ndisk int_nfilesys", "ogGetMountPoint 1 1") - return - # Error si no se reciben 2 parámetros. - if len(sys.argv) != 3: - ogRaiseError(OG_ERR_FORMAT) - return +#/** +# ogGetMountPoint int_ndisk int_nfilesys +#@brief Devuelve el punto de montaje de un sistema de archivos. +#@param int_ndisk nº de orden del disco +#@param int_nfilesys nº de orden del sistema de archivos +#@return Punto de montaje +#@exception OG_ERR_FORMAT Formato incorrecto. +#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo. +#@note Requisitos: \c mount* \c awk +#*/ ## - # Obtener partición. - PART = ogDiskToDev(int_ndisk, int_nfilesys) - if not PART: - return +def ogGetMountPoint(disk, par): + PART = DiskLib.ogDiskToDev(disk, par) + if not PART: return + + return subprocess.run(["findmnt", "-n", "-o", "TARGET", PART], capture_output=True, text=True).stdout.strip() - # Devolver punto de montaje. - result = subprocess.run(["findmnt", "-n", "-o", "TARGET", PART], capture_output=True, text=True) - return result.stdout.strip() #/** @@ -441,27 +439,31 @@ def ogIsFormated(disk, part): out = subprocess.run(["zfs", "list", "-Hp", "-o", "canmount", PART], capture_output=True, text=True).stdout.strip() return out == "on" -def ogIsLocked(int_ndisk, int_nfilesys): - return ogIsPartitionLocked(int_ndisk, int_nfilesys) -def ogIsPartitionLocked(int_ndisk, int_npartition): - # Si se solicita, mostrar ayuda. - if len(sys.argv) == 3 and sys.argv[2] == "help": - ogHelp("ogIsPartitionLocked", "ogIsPartitionLocked int_ndisk int_npartition", "ogIsPartitionLocked 1 1") - return - # Error si no se reciben 2 parámetros. - if len(sys.argv) != 3: - ogRaiseError(OG_ERR_FORMAT) - return +#/** +# ogIsLocked int_ndisk int_npartition +#@see ogIsPartitionLocked +#*/ - # Obtener partición. - PART = ogDiskToDev(int_ndisk, int_npartition) - if not PART: - return +def ogIsLocked(disk, par): + return ogIsPartitionLocked(disk, par) - # Comprobar existencia de fichero de bloqueo de la partición o de su disco. - LOCKDISK = f"/var/lock/lock{ogDiskToDev(int_ndisk).replace('/', '-')}" + +#/** +# ogIsPartitionLocked int_ndisk int_npartition +#@brief Comprueba si una partición o su disco están bloqueados por una operación de uso exclusivo. +#@param int_ndisk nº de orden del disco +#@param int_npartition nº de orden de la partición +#@return Código de salida: 0 - bloqueado, 1 - sin bloquear o error. +#@note Los ficheros de bloqueo se localizan en \c /var/lock/dev, siendo \c dev el dispositivo de la partición o de su disco, sustituyendo el carácter "/" por "-". +#*/ ## +def ogIsPartitionLocked(disk, par): + DISK = DiskLib.ogDiskToDev(disk) + PART = DiskLib.ogDiskToDev(disk, par) + if not PART: return + + LOCKDISK = f"/var/lock/lock{DISK.replace('/', '-')}" LOCKPART = f"/var/lock/lock{PART.replace('/', '-')}" return os.path.isfile(LOCKDISK) or os.path.isfile(LOCKPART) @@ -480,23 +482,22 @@ def ogIsMounted(int_ndisk, int_nfilesys): MNTDIR = ogGetMountPoint(int_ndisk, int_nfilesys) return bool(MNTDIR) -def ogIsReadonly(int_ndisk, int_nfilesys): - # Si se solicita, mostrar ayuda. - if len(sys.argv) == 3 and sys.argv[2] == "help": - ogHelp("ogIsReadonly", "ogIsReadonly int_ndisk int_nfilesys", "ogIsReadonly 1 1") - return - # Error si no se reciben 2 parámetros. - if len(sys.argv) != 3: - ogRaiseError(OG_ERR_FORMAT) - return +#/** +# ogIsReadonly int_ndisk int_nfilesys +#@brief Comprueba si un sistema de archivos está montado solo de lectura. +#@param int_ndisk nº de orden del disco +#@param int_nfilesys nº de orden del sistema de archivos +#@return Código de salida: 0 - montado solo de lectura, 1 - con escritura o no montado. +#@version 1.1.0 - Primera versión para OpenGnsys. +#@author Ramon Gomez, ETSII Universidad de Sevilla +#@date 2016-01-20 +#*/ ## - # Obtener partición. - PART = ogDiskToDev(int_ndisk, int_nfilesys) - if not PART: - return +def ogIsReadonly(disk, par): + PART = DiskLib.ogDiskToDev(disk, par) + if not PART: return - # Comprobar si la partición está montada en modo de solo lectura. result = subprocess.run(["findmnt", "-n", "-o", "OPTIONS", PART], capture_output=True, text=True) options = result.stdout.strip().split(",") return "ro" in options @@ -545,14 +546,19 @@ def ogLockPartition(int_ndisk, int_npartition): LOCKFILE = f"/var/lock/lock{PART.replace('/', '-')}" open(LOCKFILE, 'a').close() -def ogMount(): - args = sys.argv[2:] - if args == ["CACHE"] or args == ["cache"]: - ogMountCache() - elif args == ["CDROM"] or args == ["cdrom"]: - ogMountCdrom() - else: - ogMountFs(*args) + +#/** +# ogMount int_ndisk int_nfilesys +#@see ogMountFs ogMountCache ogMountCdrom +#*/ ## +def ogMount(*args): + if 1 == len (args): + if 'cache' == args[0].lower(): + return ogMountCache() + elif 'cdrom' == args[0].lower(): + return ogMountCdrom() + elif 2 == len (args): + return ogMountFs(args[0], args[1]) def ogMountFirstFs(int_ndisk): # Obtener número de particiones del disco. @@ -564,65 +570,87 @@ def ogMountFirstFs(int_ndisk): ogRaiseError(OG_ERR_NOTFOUND, int_ndisk) return OG_ERR_NOTFOUND -def ogMountFs(int_ndisk, int_nfilesys): - FUNCNAME = ogExecAndLog.__name__ - # Si se solicita, mostrar ayuda. - if len(sys.argv) == 3 and sys.argv[2] == "help": - ogHelp(f"{FUNCNAME}", "{FUNCNAME} int_ndisk int_nfilesys", "{FUNCNAME} 1 1 => /mnt/sda1") +#/** +# ogMountFs int_ndisk int_nfilesys +#@brief Monta un sistema de archivos. +#@param int_ndisk nº de orden del disco +#@param int_nfilesys nº de orden del sistema de archivos +#@return Punto de montaje +#@exception OG_ERR_FORMAT Formato incorrecto. +#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo. +#@exception OG_ERR_PARTITION Tipo de particion desconocido o no se puede montar. +#*/ ## + +def ogMountFs (disk, par): + dev = DiskLib.ogDiskToDev (disk, par) + if not dev: return + + mntdir = ogGetMountPoint (disk, par) + if mntdir: return mntdir + + if ogIsLocked (disk, par): + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_LOCKED, f"{ogGlobals.lang.MSG_PARTITION}, {disk} {par}") return - # Error si no se reciben 2 parámetros. - if len(sys.argv) != 3: - ogRaiseError(OG_ERR_FORMAT) - return - - # Obtener partición. - PART = ogDiskToDev(int_ndisk, int_nfilesys) - if not PART: - return - - # Comprobar si el sistema de archivos ya está montada. - MNTDIR = ogGetMountPoint(int_ndisk, int_nfilesys) - # Si no, montarlo en un directorio de sistema. - if not MNTDIR: - # Error si la particion esta bloqueada. - if ogIsLocked(int_ndisk, int_nfilesys): - ogRaiseError(OG_ERR_LOCKED, f"{MSG_PARTITION}, {int_ndisk} {int_nfilesys}") - return - - # El camino de un dispositivo normal comienza por el carácter "/". - if PART.startswith("/"): - # Crear punto de montaje o enlace simbólico para caché local. - MNTDIR = PART.replace("/dev", "/mnt") - DEBUG = "no" - if f"{int_ndisk} {int_nfilesys}" == ogFindCache() and OGCAC: - os.makedirs(OGCAC, exist_ok=True) - os.symlink(OGCAC, MNTDIR) - else: - os.makedirs(MNTDIR, exist_ok=True) - del DEBUG - - # Montar sistema de archivos. + # El camino de un dispositivo normal comienza por el carácter "/". + if dev.startswith ('/'): + # Crear punto de montaje o enlace simbólico para caché local. + mntdir = dev.replace ('/dev', '/mnt') + if f"{disk} {par}" == CacheLib.ogFindCache(): + os.makedirs(ogGlobals.OGCAC, exist_ok=True) try: - subprocess.run(["mount", PART, MNTDIR], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except subprocess.CalledProcessError: - try: - subprocess.run(["mount", PART, MNTDIR, "-o", "force,remove_hiberfile"], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except subprocess.CalledProcessError: - ogRaiseError(OG_ERR_PARTITION, f"{int_ndisk}, {int_nfilesys}") - return - # Aviso de montaje de solo lectura. - if ogIsReadonly(int_ndisk, int_nfilesys): - ogEcho("warning", f"{FUNCNAME}: {MSG_MOUNTREADONLY}: \"{int_ndisk}, {int_nfilesys}\"") - else: - # Montar sistema de archivos ZFS (un ZPOOL no comienza por "/"). - try: - subprocess.run(["zfs", "mount", PART], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) - except subprocess.CalledProcessError: + os.symlink(ogGlobals.OGCAC, mntdir) + except FileExistsError: pass + else: + os.makedirs(mntdir, exist_ok=True) - return MNTDIR + # Montar sistema de archivos. + try: + rc = subprocess.run(['mount', dev, mntdir], check=True).returncode + except subprocess.CalledProcessError: + try: + rc = subprocess.run(['mount', dev, mntdir, '-o', 'force,remove_hiberfile'], check=True).returncode + except subprocess.CalledProcessError: + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, f"{disk}, {par}") + return + if 0 == rc: + pass + elif 14 == rc: + try: + subprocess.run (['ntfsfix', '-d', par], check=True) + except subprocess.CalledProcessError: + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, f"{disk, par}") + #return + else: + try: + subprocess.run (['mount', par, mntdir, '-o', 'ro'], check=True) + except subprocess.CalledProcessError: + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, f"{disk, par}") + #return + + # Aviso de montaje de solo lectura. + if ogIsReadonly(disk, par): + SystemLib.ogEcho("warning", f'ogMountFs: {ogGlobals.lang.MSG_MOUNTREADONLY}: "{disk}, {par}"') + else: + # Montar sistema de archivos ZFS (un ZPOOL no comienza por "/"). + subprocess.run(['zfs', 'mount', dev]) + + return mntdir + + + +#/** +# ogMountCdrom +#@brief Monta dispositivo óptico por defecto +#@return Punto de montaje +#@exception OG_ERR_FORMAT Formato incorrecto. +#@exception OG_ERR_PARTITION Tipo de particion desconocido o no se puede montar. +#@version +#@author +#@date +#*/ ## def ogMountCdrom(): DEV = "/dev/cdrom" # Por defecto MNTDIR = subprocess.run(["mount", "-l", "-t", "iso9660", DEV], capture_output=True, text=True) @@ -633,7 +661,7 @@ def ogMountCdrom(): try: subprocess.run(["mount", "-t", "iso9660", DEV, MNTDIR], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) except subprocess.CalledProcessError: - ogRaiseError(OG_ERR_PARTITION, "cdrom") + SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, "cdrom") return return MNTDIR diff --git a/client/lib/engine/bin/ogGlobals.py b/client/lib/engine/bin/ogGlobals.py index 342eeb2..bf9c1b9 100755 --- a/client/lib/engine/bin/ogGlobals.py +++ b/client/lib/engine/bin/ogGlobals.py @@ -1,8 +1,9 @@ #!/usr/bin/python3 import sys +import os.path import locale -import importlib +import importlib.util def load_lang (name): global lang @@ -27,17 +28,25 @@ TZ='Europe/Madrid' ## engine.cfg +OGLOGSESSION='/tmp/session.log' +OGLOGCOMMAND='/tmp/command.log' NODEBUGFUNCTIONS='ogCreateImageSyntax ogGetHivePath ogGetOsType ogRestoreImageSyntax ogUnmountAll ogUnmountCache' ## /engine.cfg -#OPENGNSYS='/opt/opengnsys' -OPENGNSYS='/tmp/opengnsys' ## XXX -OGLOG=f'{OPENGNSYS}/log' -OGLOGFILE=f'{OGLOG}/192.168.42.42' ## TODO -OGLOGCOMMAND='/tmp/command.log' -OGLOGSESSION='/tmp/session.log' -DEBUG='yes' +## loadenviron.sh +OPENGNSYS = '/opt/opengnsys' +OGBIN = os.path.join (OPENGNSYS, 'bin') +OGETC = os.path.join (OPENGNSYS, 'etc') +OGLIB = os.path.join (OPENGNSYS, 'lib') +OGAPI = os.path.join (OGLIB, 'engine', 'bin') +OGSCRIPTS = os.path.join (OPENGNSYS, 'scripts') +OGIMG = os.path.join (OPENGNSYS, 'images') +OGCAC = os.path.join (OPENGNSYS, 'cache') +OGLOG = os.path.join (OPENGNSYS, 'log') +OGLOGFILE = f'{OGLOG}/192.168.42.42' ## TODO import NetLib; OGLOGFILE = f'$OGLOG/{NetLib.ogGetIpAddress()}.log' +DEBUG = 'yes' +## /loadenviron.sh # Declaración de códigos de error. OG_ERR_FORMAT=1 # Formato de ejecución incorrecto.