ogclone-engine/client/lib/engine/bin/DiskLib.py

1418 lines
50 KiB
Python

#/**
#@file DiskLib.py
#@brief Librería o clase Disk
#@class Disk
#@brief Funciones para gestión de discos y particiones.
#@warning License: GNU GPLv3+
#*/
import filecmp
import subprocess
import shutil
import os
import re
import stat
from pathlib import Path
import ogGlobals
import SystemLib
import CacheLib
import FileSystemLib
import InventoryLib
# Función ficticia para lanzar parted con timeout, evitando cuelgues del programa.
def parted(*args):
parted_path = shutil.which("parted")
if parted_path:
try:
result = subprocess.run(
[parted_path] + list(args),
timeout=3,
capture_output=True,
text=True
)
return result.stdout
except subprocess.TimeoutExpired:
return "Error: Command 'parted' timed out"
else:
return "Error: 'parted' command not found"
#/**
# ogCreatePartitions int_ndisk str_parttype:int_partsize ...
#@brief Define el conjunto de particiones de un disco.
#@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 cache 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 ogCreatePartitions (disk, parts):
ND = disk
DISK = ogDiskToDev (ND)
if not DISK: return None
PTTYPE = ogGetPartitionTableType (disk)
if not PTTYPE: PTTYPE = 'MSDOS' # Por defecto para discos vacíos.
if 'GPT' == PTTYPE:
return ogCreateGptPartitions (disk, parts)
elif 'MSDOS' != PTTYPE:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, PTTYPE)
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
# 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:
START = 4096
SECTORS -= 8192
if CACHESIZE:
SECTORS = SECTORS - CACHESIZE + 2048 - (SECTORS - CACHESIZE) % 2048 - 1
else:
START = 63
if CACHESIZE:
SECTORS -= CACHESIZE
PART = 1
sfdisk_input = 'unit: sectors\n\n'
NVME_PREFIX = 'p' if 'nvme' in DISK else ''
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
# 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
# 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 si la partición es extendida.
EXTSTART = EXTSIZE = 0
if 5 == ID:
if PART > 4:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, '')
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
# 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'
START += SIZE
# Error si se supera el nº total de sectores.
if '4096' == IOSIZE and PART > 4:
START += 2048
if START > SECTORS:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'{START//2} > {SECTORS//2}')
return None
PART += 1
# Si no se indican las 4 particiones primarias, definirlas como vacías, conservando la partición de caché.
while PART <= 4:
if f'{ND} {PART}' == CACHEPART and CACHESIZE:
sfdisk_input += f'{DISK}{NVME_PREFIX}{PART} : start={SECTORS+1}, size={CACHESIZE}, Id=ca\n'
else:
sfdisk_input += f'{DISK}{NVME_PREFIX}{PART} : start=0, size=0, Id=0\n'
PART += 1
# Si se define partición extendida sin lógicas, crear particion 5 vacía.
if 5 == PART and EXTSTART:
sfdisk_input += f'{DISK}5 : start={EXTSTART}, SIZE={EXTSIZE}, Id=0\n'
# Desmontar los sistemas de archivos del disco antes de realizar las operaciones.
FileSystemLib.ogUnmountAll (ND)
if CACHESIZE: CacheLib.ogUnmountCache()
# Si la tabla de particiones no es valida, volver a generarla.
ogCreatePartitionTable (ND)
# Definir particiones y notificar al kernel.
subprocess.run (['sfdisk', DISK], input=sfdisk_input, capture_output=True, text=True)
subprocess.run (['partprobe', DISK])
if CACHESIZE: CacheLib.ogMountCache()
return True
#/**
# 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
# 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.
subprocess.run (['sgdisk'] + DELOPTIONS + OPTIONS + [DISK])
subprocess.run (['partprobe', DISK])
if CACHESIZE: CacheLib.ogMountCache()
return True
#/**
# ogCreatePartitionTable int_ndisk [str_tabletype]
#@brief Genera una tabla de particiones en caso de que no sea valida, si es valida no hace nada.
#@param int_ndisk nº de orden del disco
#@param str_tabletype tipo de tabla de particiones (opcional)
#@return (por determinar)
#@exception OG_ERR_FORMAT Formato incorrecto.
#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo.
#@note tabletype: { MSDOS, GPT }, MSDOS por defecto
#@note Requisitos: fdisk, gdisk, parted
#*/ ##
def ogCreatePartitionTable (disk, createptt=None):
DISK = ogDiskToDev (disk)
if not DISK: return None
pttype = ogGetPartitionTableType (disk) or 'MSDOS' # Por defecto para discos vacíos.
createptt = createptt or pttype
CREATE = None
# Si la tabla actual y la que se indica son iguales, se comprueba si hay que regenerarla.
if createptt == pttype:
if 'GPT' == pttype:
try:
result = subprocess.run (['sgdisk', '-p', DISK], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if result.returncode:
CREATE = 'GPT'
except subprocess.CalledProcessError:
CREATE = 'GPT'
elif 'MSDOS' == pttype:
try:
result = subprocess.run (['parted', '-s', DISK, 'print'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
if result.returncode:
CREATE = 'MSDOS'
except subprocess.CalledProcessError:
CREATE = 'MSDOS'
else:
CREATE = createptt.upper()
# Dependiendo del valor de CREATE, creamos la tabla de particiones en cada caso.
if 'GPT' == CREATE:
if 'MSDOS' == pttype:
subprocess.run (['sgdisk', '-go', DISK])
else:
subprocess.run (['gdisk', DISK], input='2\nw\nY\n', text=True)
subprocess.run (['partprobe', DISK])
elif 'MSDOS' == CREATE:
if 'GPT' == pttype:
subprocess.run (['sgdisk', '-Z', DISK])
# Crear y borrar una partición para que la tabla se genere bien.
subprocess.run (['fdisk', DISK], input='o\nn\np\n\n\n\nd\n\nw', text=True)
subprocess.run (['partprobe', DISK])
return None
#/**
# ogDeletePartitionTable ndisk
#@brief Borra la tabla de particiones del disco.
#@param int_ndisk nº de orden del disco
#@return la informacion propia del fdisk
#*/ ##
def ogDeletePartitionTable (disk):
DISK = ogDiskToDev (disk)
if not DISK: return None
PTTYPE = ogGetPartitionTableType (disk)
if 'GPT' == PTTYPE:
subprocess.run (['sgdisk', '--clear', DISK])
elif 'MSDOS' == PTTYPE:
subprocess.run (['fdisk', DISK], input='o\nw', text=True)
return
#/**
# ogDevToDisk path_device | LABEL="str_label" | UUID="str_uuid"
#@brief Devuelve el nº de orden de dicso (y partición) correspondiente al nombre de fichero de dispositivo o a la etiqueta o UUID del sistema de archivos asociado.
#@param path_device Camino del fichero de dispositivo.
#@param str_label etiqueta de sistema de archivos.
#@param str_uuid UUID de sistema de archivos.
#@return int_ndisk (para dispositivo de disco)
#@return int_ndisk int_npartition (para dispositivo de partición).
#@exception OG_ERR_FORMAT Formato incorrecto.
#@exception OG_ERR_NOTFOUND Dispositivo no detectado.
#@note Solo se acepta en cada llamada 1 de los 3 tipos de parámetros.
#*/ ##
def ogDevToDisk(arg_dev):
CACHEFILE = "/var/cache/disks.cfg"
if '=' in arg_dev:
# arg_dev is "FOO=bar"
cmd = None
if arg_dev.startswith("LABEL="): cmd = ['blkid', '-L', arg_dev[6:]]
elif arg_dev.startswith("PARTLABEL="): cmd = ['realpath', '/dev/disk/by-partlabel/'+arg_dev[11:]]
elif arg_dev.startswith("PARTUUID="): cmd = ['realpath', '/dev/disk/by-partuuid/'+arg_dev[10:]]
elif arg_dev.startswith("UUID="): cmd = ['blkid', '-U', arg_dev[5:]]
if not cmd:
SystemLib.ogRaiseError([], ogGlobals.OG_ERR_FORMAT, arg_dev)
return
DEV = subprocess.run (cmd, capture_output=True, text=True).stdout.strip()
else:
# arg_dev is "/dev/something"
DEV = arg_dev
if not os.path.exists(DEV):
SystemLib.ogRaiseError([], ogGlobals.OG_ERR_NOTFOUND, arg_dev)
return
# Error si no es fichero de bloques o directorio (para LVM).
m = os.stat (DEV, follow_symlinks=True).st_mode
if not stat.S_ISBLK (m) and not stat.S_ISDIR (m):
SystemLib.ogRaiseError([], ogGlobals.OG_ERR_NOTFOUND, arg_dev)
return
# Buscar en fichero de caché de discos.
PART = None
if os.path.exists(CACHEFILE):
with open(CACHEFILE, 'r') as f:
for line in f:
parts = line.strip().split(':')
if len(parts) == 2 and parts[1] == DEV:
PART = parts[0]
break
if PART: return PART
# Si no se encuentra, procesa todos los discos para devolver su nº de orden y de partición.
disks = ogDiskToDev()
n = 1
for d in disks:
NVME_PREFIX = "p" if "nvme" in d else ""
if DEV.startswith(d):
return f"{n} {DEV[len(d) + len(NVME_PREFIX):]}"
n += 1
SystemLib.ogRaiseError([], ogGlobals.OG_ERR_NOTFOUND, arg_dev)
return
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()
for line in all_disks:
parts = line.split()
if parts[5] == "disk":
parts[0].replace ('!', '/')
ret.append(f"/dev/{parts[0]}")
return ret
def _getAllVolGroups():
vgs = subprocess.run(['vgs', '-a', '--noheadings'], capture_output=True, text=True).stdout.splitlines()
ret = [f"/dev/{line.split()[0]}" for line in vgs]
return ret
def _getMPath():
ret = alldisks2remove = []
try:
mpath = subprocess.run(['multipath', '-l', '-v', '1'], capture_output=True, text=True).stdout.splitlines()
ret = [f"/dev/mapper/{line.split()[0]}" for line in mpath]
for line in subprocess.getoutput("multipath -ll").splitlines():
if line.split()[5] == "ready":
alldisks2remove.append (f"/dev/{line.split()[2]}")
except FileNotFoundError:
pass
except subprocess.CalledProcessError:
pass
return ret, alldisks2remove
def _getAllZFSVols():
zfsvols = subprocess.run(['blkid'], capture_output=True, text=True).stdout.splitlines()
return [line.split(":")[0] for line in zfsvols if "zfs" in line]
#/**
# ogDiskToDev [int_ndisk [int_npartition]]
#@brief Devuelve la equivalencia entre el nº de orden del dispositivo (dicso o partición) y el nombre de fichero de dispositivo correspondiente.
#@param int_ndisk nº de orden del disco
#@param int_npartition nº de orden de la partición
#@return Para 0 parametros: Devuelve los nombres de ficheros de los dispositivos sata/ata/usb linux encontrados.
#@return Para 1 parametros: Devuelve la ruta del disco duro indicado.
#@return Para 2 parametros: Devuelve la ruta de la particion indicada.
#@exception OG_ERR_FORMAT Formato incorrecto.
#@exception OG_ERR_NOTFOUND Dispositivo no detectado.
#*/ ##
def ogDiskToDev (arg_disk=None, arg_part=None):
CACHEFILE = "/var/cache/disks.cfg"
try:
if arg_part != None:
arg_part = int (arg_part)
except:
SystemLib.ogRaiseError([], ogGlobals.OG_ERR_FORMAT, f"{arg_disk} {arg_part}")
return
try:
if arg_disk != None:
arg_disk = int (arg_disk)
except:
SystemLib.ogRaiseError([], ogGlobals.OG_ERR_FORMAT, arg_disk)
return
# Borrar fichero de caché de configuración si hay cambios en las particiones.
proc_partitions = Path ('/proc/partitions').read_text()
tmp_partitions = Path ('/tmp/.partitions').read_text() if os.path.exists ('/tmp/.partitions') else ''
if proc_partitions != tmp_partitions:
# Guardar copia de las particiones definidas para comprobar cambios.
shutil.copy2('/proc/partitions', '/tmp/.partitions')
try:
os.remove(CACHEFILE)
except FileNotFoundError:
pass
# Si existe una correspondencia con disco/dispositivo en el caché; mostrarlo y salir.
if arg_disk and os.path.exists (CACHEFILE):
with open(CACHEFILE, 'r') as f:
args_joined = ' '.join (map (str, filter (None, [arg_disk,arg_part])))
for line in f:
parts = line.strip().split(':')
if len(parts) == 2 and parts[0] == args_joined:
return parts[1]
# Continuar para detectar nuevos dispositivos.
ALLDISKS = _getAllDisks()
VOLGROUPS = _getAllVolGroups()
ALLDISKS += VOLGROUPS
MPATH, ALLDISKS_to_remove =_getMPath()
for d in ALLDISKS_to_remove:
if d in ALLDISKS: ALLDISKS.remove (d)
ZFSVOLS = _getAllZFSVols()
ALLDISKS += ZFSVOLS
# No params: return all disks
if arg_disk is None:
return ALLDISKS
# arg_disk is set: return it
if arg_part is None:
if arg_disk > len (ALLDISKS):
SystemLib.ogRaiseError([], ogGlobals.OG_ERR_NOTFOUND, arg_disk)
return
disk = ALLDISKS[arg_disk-1]
if not os.path.exists(disk):
SystemLib.ogRaiseError([], ogGlobals.OG_ERR_NOTFOUND, arg_disk)
return
# Actualizar caché de configuración y mostrar dispositivo.
with open(CACHEFILE, 'a') as f:
f.write(f"{arg_disk}:{disk}\n")
return disk
# arg_disk and arg_part are set: there are several possibilities
if arg_disk > len (ALLDISKS):
SystemLib.ogRaiseError([], ogGlobals.OG_ERR_NOTFOUND, arg_disk)
return
disk = ALLDISKS[arg_disk-1]
if not os.path.exists(disk):
SystemLib.ogRaiseError([], ogGlobals.OG_ERR_NOTFOUND, arg_disk)
return
# Plain partition
part = f"{disk}{arg_part}"
if os.path.exists(part):
# Actualizar caché de configuración y mostrar dispositivo.
with open(CACHEFILE, 'a') as f:
f.write(f"{arg_disk} {arg_part}:{part}\n")
return part
# RAID/Multipath (tener en cuenta enlace simbólico).
part = f"{disk}p{arg_part}"
if os.path.exists(part) and stat.S_ISBLK (os.stat (part, follow_symlinks=True).st_mode):
# Actualizar caché de configuración y mostrar dispositivo.
with open(CACHEFILE, 'a') as f:
f.write(f"{arg_disk} {arg_part}:{part}\n")
return part
part = ""
# Logical volume
if disk in VOLGROUPS:
lvscan = subprocess.run (['lvscan', '-a'], capture_output=True, text=True).stdout.splitlines()
i = 0
for line in lvscan:
parts = line.split("'")
if parts[1].startswith(f"{disk}/") and i == arg_part:
part = parts[1]
break
i += 1
# ZFS volume
if disk in ZFSVOLS:
subprocess.run(["zpool", "import", "-f", "-R", "/mnt", "-N", "-a"])
zpool = subprocess.run(['blkid', '-s', 'LABEL', '-o', 'value', disk], capture_output=True, text=True).stdout
zfs_list = subprocess.run(['zfs', 'list', '-Hp', '-o', 'name,canmount,mountpoint', '-r', zpool], capture_output=True, text=True).stdout.splitlines()
i = 0
for line in zfs_list:
parts = line.split()
if parts[1] == "on" and parts[2] != "none":
if i == int(args[1]):
part = parts[0]
break
i += 1
if not part:
SystemLib.ogRaiseError([], ogGlobals.OG_ERR_NOTFOUND, f"{arg_disk} {arg_part}")
return
# Actualizar caché de configuración y mostrar dispositivo.
with open(CACHEFILE, 'a') as f:
f.write(f"{arg_disk} {arg_part}:{part}\n")
return part
#/**
# ogGetDiskSize int_ndisk
#@brief Muestra el tamaño en KB de un disco.
#@param int_ndisk nº de orden del disco
#@return int_size - Tamaño en KB del disco.
#@exception OG_ERR_FORMAT formato incorrecto.
#@exception OG_ERR_NOTFOUND disco o particion no detectado (no es un dispositivo).
#@note Requisitos: sfdisk, awk
#*/ ##
def ogGetDiskSize (disk):
DISK = ogDiskToDev (disk)
if not DISK: return None
bn = os.path.basename (DISK)
SIZE = None
with open ('/proc/partitions', 'r') as fd:
while True:
l = fd.readline()
if not l: break
items = l.split()
if len(items) < 4: continue
if items[3] == bn:
SIZE = int (items[2])
break
if not SIZE:
vgs_out = subprocess.run (['vgs', '--noheadings', '--units=B', '-o', 'dev_size', DISK], capture_output=True, text=True).stdout
items = vgs_out.split()
SIZE = int (items[0]) // 1024
return SIZE
#/**
# ogGetDiskType path_device
#@brief Muestra el tipo de disco (real, RAID, meta-disco, USB, etc.).
#@param path_device Dispositivo
#@exception OG_ERR_FORMAT formato incorrecto.
#@exception OG_ERR_NOTFOUND disco no detectado o no es un dispositivo de bloques.
#@note Requisitos: udevadm
#*/ ##
def ogGetDiskType (dev):
DEV = os.path.basename (dev)
bn = os.path.basename (DEV)
MAJOR = None
with open ('/proc/partitions', 'r') as fd:
while True:
l = fd.readline()
if not l: break
items = l.split()
if len(items) < 4: continue
if items[3] == bn:
MAJOR = items[0]
break
TYPE = None
with open ('/proc/devices', 'r') as fd:
within_block_section = False
while True:
l = fd.readline()
if not l: break
if 'Block' in l:
within_block_section = True
continue
if not within_block_section:
continue
items = l.split()
if len(items) < 2: continue
if items[0] == MAJOR:
TYPE = items[1].upper()
break
# Devolver mnemónico del driver de dispositivo.
if 'SD' == TYPE:
TYPE = 'DISK'
udevadm_out = subprocess.run (['udevadm', 'info', '-q', 'property', dev], capture_output=True, text=True).stdout
for l in udevadm_out.splitlines():
if 'ID_BUS=usb' == l[0:10]:
TYPE = 'USB'
elif 'BLKEXT' == TYPE:
TYPE = 'NVM'
elif 'SR' == TYPE or TYPE.startswith ('IDE'):
TYPE = 'CDROM' # FIXME Comprobar discos IDE.
elif 'MD' == TYPE or TYPE.startswith ('CCISS'):
TYPE = 'RAID'
elif 'DEVICE-MAPPER' == TYPE:
TYPE = 'MAPPER' # FIXME Comprobar LVM y RAID.
return TYPE
#/**
# ogGetEsp
#@brief Devuelve números de disco y partición para la partición EFI (ESP).
#*/ ##
def ogGetEsp():
devices = subprocess.run (['blkid', '-o', 'device'], capture_output=True, text=True).stdout.splitlines()
devices.sort()
for d in devices:
# Previene error para /dev/loop0
PART = ogDevToDisk (d)
if not PART: continue
# En discos NVMe blkid devuelve una salida del tipo:
# >/dev/loop0
# >/dev/nvme0n1
# >/dev/nvme0n1p1
# al analizar la particion nvme0n1, PART solo tiene un argumento y hace que ogGetPartitionId lance un error
if len (PART) > 1:
disk, par = PART.split()
if ogGetPartitionId (disk, par) == ogTypeToId ('EFI', 'GPT'):
return PART
return None
#/**
# ogGetLastSector int_ndisk [int_npart]
#@brief Devuelve el último sector usable del disco o de una partición.
#@param int_ndisk nº de orden del disco
#@param int_npart nº de orden de la partición (opcional)
#@return Último sector usable.
#@exception OG_ERR_FORMAT Formato incorrecto.
#@exception OG_ERR_NOTFOUND Disco o partición no corresponde con un dispositivo.
#@note Requisitos: sfdisk, sgdisk
#*/ ##
def ogGetLastSector (disk, par=None):
DISK = ogDiskToDev (disk)
if not DISK: return None
env = os.environ
env['LANG'] = 'C'
last = None
if par:
PART = ogDiskToDev (disk, par)
if not PART: return None
sgdisk_out = subprocess.run (['sgdisk', '-p', DISK], env=env, capture_output=True, text=True).stdout
for l in sgdisk_out.splitlines():
items = l.split()
if len(items) < 3: continue
if str (par) != items[0]: continue
last = int (items[2])
break
else:
sgdisk_out = subprocess.run (['sgdisk', '-p', DISK], env=env, capture_output=True, text=True).stdout
for l in sgdisk_out.splitlines():
if 'last usable sector' not in l: continue
items = l.split()
last = int (items[-1])
return last
#/**
# ogGetPartitionActive int_ndisk
#@brief Muestra que particion de un disco esta marcada como de activa.
#@param int_ndisk nº de orden del disco
#@exception OG_ERR_FORMAT Formato incorrecto.
#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo.
#@note Requisitos: parted
#@todo Queda definir formato para atributos (arranque, oculta, ...).
#*/ ##
def ogGetPartitionActive (disk):
DISK = ogDiskToDev (disk)
if DISK is None: return
if 'LANG' in os.environ:
lang = os.environ['LANG']
ret = None
os.environ['LANG'] = 'C'
lines = subprocess.run (['parted', '--script', '--machine', DISK, 'print'], capture_output=True, text=True).stdout.splitlines()
for line in lines:
parts = line.split (':')
if len (parts) < 6: continue
if 'boot' in parts[6]:
ret = parts[0]
break
if lang is None:
del os.environ['LANG']
else:
os.environ['LAMG'] = lang
return ret
#/**
# ogGetPartitionId int_ndisk int_npartition
#@brief Devuelve el mnemónico con el tipo de partición.
#@param int_ndisk nº de orden del disco
#@param int_npartition nº de orden de la partición
#@return Identificador de tipo de partición.
#@exception OG_ERR_FORMAT Formato incorrecto.
#@exception OG_ERR_NOTFOUND Disco o partición no corresponde con un dispositivo.
#@note Requisitos: sfdisk
#*/ ##
def ogGetPartitionId (disk, par):
DISK = ogDiskToDev (disk)
if DISK is None: return
fsid = None
pttype = ogGetPartitionTableType (disk)
if 'GPT' == pttype:
lines = subprocess.run (['sgdisk', '-p', DISK], capture_output=True, text=True).stdout.splitlines()
start_index = next (i for i, line in enumerate(lines) if 'Number' in line)
for l in lines[start_index:]:
idx, start, end, sz, sz_units, code, *rest = l.split()
if idx == str(par):
fsid = code
break
if fsid == '8300' and f'{disk} {par}' == CacheLib.ogFindCache():
fsid = 'CA00'
elif 'MSDOS' == pttype:
fsid = subprocess.run (['sfdisk', '--part-type', DISK, par], capture_output=True, text=True).stdout.strip()
elif 'LVM' == pttype:
fsid = '10000'
elif 'ZPOOL' == pttype:
fsid = '10010'
return fsid
#/**
# ogGetPartitionSize int_ndisk int_npartition
#@brief Muestra el tamano en KB de una particion determinada.
#@param int_ndisk nº de orden del disco
#@param int_npartition nº de orden de la partición
#@return int_partsize - Tamaño en KB de la partición.
#@exception OG_ERR_FORMAT formato incorrecto.
#@exception OG_ERR_NOTFOUND disco o particion no detectado (no es un dispositivo).
#@note Requisitos: sfdisk, awk
#*/ ##
def ogGetPartitionSize (disk, par):
PART = ogDiskToDev (disk, par)
if PART is None: return
sz = subprocess.run (['partx', '-gbo', 'SIZE', PART], capture_output=True, text=True).stdout.strip()
if sz: return int (int (sz) / 1024)
sz = subprocess.run (['lvs', '--noheadings', '-o', 'lv_size', '--units', 'k', PART], capture_output=True, text=True).stdout.strip()
if sz: return int (sz)
return FileSystemLib.ogGetFsSize (disk, par)
#/**
# ogGetPartitionsNumber int_ndisk
#@brief Detecta el numero de particiones del disco duro indicado.
#@param int_ndisk nº de orden del disco
#@return Devuelve el numero paritiones del disco duro indicado
#@warning Salidas de errores no determinada
#@attention Requisitos: parted
#@note Notas sin especificar
#*/ ##
def ogGetPartitionsNumber (disk):
DISK = ogDiskToDev (disk)
if not DISK: return None
out = 0
pttype = ogGetPartitionTableType (disk)
if pttype in ['GPT', 'MSDOS']:
partx_out = subprocess.run (['partx', '-gso', 'NR', DISK], capture_output=True, text=True).stdout
lines = partx_out.splitlines()
if len(lines):
out = lines[-1].strip()
elif 'LVM' == pttype:
lvs_out = subprocess.run (['lvs', '--noheadings', DISK], capture_output=True, text=True).stdout
lines = lvs_out.splitlines()
out = len (lines)
elif 'ZPOOL' == pttype:
if subprocess.run (['zpool', 'list']).returncode:
subprocess.run (['modprobe', 'zfs'])
subprocess.run (['zpool', 'import', '-f', '-R', '/mnt', '-N', '-a'])
blkid = subprocess.run (['blkid', '-s', 'LABEL', '-o', 'value', DISK], capture_output=True, text=True).stdout
zfs_out = subprocess.run (['zfs', 'list', '-Hp', '-o', 'name,canmount,mountpoint', '-r', blkid], capture_output=True, text=True).stdout
out = 0
for l in zfs_out.splitlines():
items = l.split()
if len(items) < 3: continue
if 'on' == items[1] and 'none' != items[2]: out += 1
return int (out)
#/**
# ogGetPartitionTableType int_ndisk
#@brief Devuelve el tipo de tabla de particiones del disco (GPT o MSDOS)
#@param int_ndisk nº de orden del disco
#@return str_tabletype - Tipo de tabla de paritiones
#@warning Salidas de errores no determinada
#@note tabletype = { MSDOS, GPT }
#@note Requisitos: blkid, parted, vgs
#*/ ##
def ogGetPartitionTableType (disk):
DISK = ogDiskToDev (disk)
if DISK is None: return
m = os.stat (DISK, follow_symlinks=True).st_mode
if stat.S_ISBLK (m):
lines = subprocess.run (['parted', '--script', '--machine', DISK, 'print'], capture_output=True, text=True).stdout.splitlines()
for l in lines:
elems = l.split (':')
if DISK == elems[0]:
type = elems[5].upper()
break
# Comprobar si es volumen lógico.
if os.path.isdir (DISK) and 0 == subprocess.run (['vgs', DISK]).returncode:
type = 'LVM'
# Comprobar si es pool de ZFS.
if not type or 'UNKNOWN' == type:
if 'zfs' in subprocess.run (['blkid', '-s', 'TYPE', DISK], capture_output=True, text=True).stdout:
type = 'ZPOOL'
return type
#/**
# ogGetPartitionType int_ndisk int_npartition
#@brief Devuelve el mnemonico con el tipo de partición.
#@param int_ndisk nº de orden del disco
#@param int_npartition nº de orden de la partición
#@return Mnemonico
#@note Mnemonico: valor devuelto por ogIdToType.
#@exception OG_ERR_FORMAT Formato incorrecto.
#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo.
#*/ ##
def ogGetPartitionType (disk, par):
ID = ogGetPartitionId (disk, par)
if ID is None: return None
return ogIdToType (ID)
#/**
# ogHidePartition int_ndisk int_npartition
#@brief Oculta un apartición visible.
#@param int_ndisk nº de orden del disco
#@param int_npartition nº de orden de la partición
#@return (nada)
#@exception OG_ERR_FORMAT formato incorrecto.
#@exception OG_ERR_NOTFOUND disco o particion no detectado (no es un dispositivo).
#@exception OG_ERR_PARTITION tipo de partición no reconocido.
#*/ ##
def ogHidePartition (disk, par):
PART = ogDiskToDev (disk, par)
if not PART: return None
TYPE = ogGetPartitionType (disk, par)
if 'NTFS' == TYPE: NEWTYPE = 'HNTFS'
elif 'FAT32' == TYPE: NEWTYPE = 'HFAT32'
elif 'FAT16' == TYPE: NEWTYPE = 'HFAT16'
elif 'FAT12' == TYPE: NEWTYPE = 'HFAT12'
elif 'WINDOWS' == TYPE: NEWTYPE = 'WIN-RESERV'
else:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, TYPE)
return None
ogSetPartitionType (disk, par, NEWTYPE)
#/**
# ogIdToType int_idpart
#@brief Devuelve el identificador correspondiente a un tipo de partición.
#@param int_idpart identificador de tipo de partición.
#@return str_parttype mnemónico de tipo de partición.
#@exception OG_ERR_FORMAT Formato incorrecto.
#*/ ##
def ogIdToType (ID):
# Obtener valor hexadecimal de 4 caracteres rellenado con 0 por delante.
ID = ID.zfill(4).lower()
id2type = {
'0000': 'EMPTY',
'0001': 'FAT12',
'0005': 'EXTENDED',
'000f': 'EXTENDED',
'0006': 'FAT16',
'000e': 'FAT16',
'0007': 'NTFS',
'000b': 'FAT32',
'000c': 'FAT32',
'0011': 'HFAT12',
'0012': 'COMPAQDIAG',
'0016': 'HFAT16',
'001e': 'HFAT16',
'0017': 'HNTFS',
'001b': 'HFAT32',
'001c': 'HFAT32',
'0042': 'WIN-DYNAMIC',
'0082': 'LINUX-SWAP',
'8200': 'LINUX-SWAP',
'0083': 'LINUX',
'8300': 'LINUX',
'008e': 'LINUX-LVM',
'8E00': 'LINUX-LVM',
'00a5': 'FREEBSD',
'a503': 'FREEBSD',
'00a6': 'OPENBSD',
'00a7': 'CACHE', # (compatibilidad con Brutalix)
'00af': 'HFS',
'af00': 'HFS',
'00be': 'SOLARIS-BOOT',
'be00': 'SOLARIS-BOOT',
'00bf': 'SOLARIS',
'bf00145': 'SOLARIS',
'00ca': 'CACHE',
'ca00': 'CACHE',
'00da': 'DATA',
'00ee': 'GPT',
'00ef': 'EFI',
'ef00': 'EFI',
'00fb': 'VMFS',
'00fd': 'LINUX-RAID',
'fd00': 'LINUX-RAID',
'0700': 'WINDOWS',
'0c01': 'WIN-RESERV',
'7f00': 'CHROMEOS-KRN',
'7f01': 'CHROMEOS',
'7f02': 'CHROMEOS-RESERV',
'8301': 'LINUX-RESERV',
'a500': 'FREEBSD-DISK',
'a501': 'FREEBSD-BOOT',
'a502': 'FREEBSD-SWAP',
'ab00': 'HFS-BOOT',
'af01': 'HFS-RAID',
'bf02': 'SOLARIS-SWAP',
'bf03': 'SOLARIS-DISK',
'ef01': 'MBR',
'ef02': 'BIOS-BOOT',
'10000': 'LVM-LV',
'10010': 'ZFS-VOL',
}
if ID in id2type:
return id2type[ID]
return 'UNKNOWN'
# ogIsDiskLocked int_ndisk
#@brief Comprueba si un disco está bloqueado por una operación de uso exclusivo.
#@param int_ndisk nº de orden del disco
#@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 ogIsDiskLocked (disk):
DISK = ogDiskToDev (disk)
if not DISK: return False
return os.path.isfile (f'/var/lock/lock{DISK.replace("/", "-")}')
#/**
# ogListPartitions int_ndisk
#@brief Lista las particiones definidas en un disco.
#@param int_ndisk nº de orden del disco
#@return str_parttype:int_partsize ...
#@exception OG_ERR_FORMAT formato incorrecto.
#@exception OG_ERR_NOTFOUND disco o particion no detectado (no es un dispositivo).
#@note Requisitos: \c parted \c awk
#@attention El nº de partición se indica por el orden de los párametros \c parttype:partsize
#@attention Las tuplas de valores están separadas por espacios.
#*/ ##
def ogListPartitions (disk):
DISK = ogDiskToDev (disk)
if not DISK: return None
p = []
NPARTS = ogGetPartitionsNumber (disk)
for PART in range (1, NPARTS + 1):
t = ogGetPartitionType (disk, PART)
TYPE = ogGetPartitionType (disk, PART) or 'EMPTY'
SIZE = ogGetPartitionSize (disk, PART) or 0
p.append (f'{TYPE}:{SIZE}')
return p
#/**
# ogListPrimaryPartitions int_ndisk
#@brief Metafunción que lista las particiones primarias no vacías de un disco.
#@param int_ndisk nº de orden del disco
#@see ogListPartitions
#*/ ##
def ogListPrimaryPartitions (disk):
PTTYPE = ogGetPartitionTableType (disk)
if not PTTYPE: return None
PARTS = ogListPartitions (disk)
if not PARTS: return None
if 'GPT' == PTTYPE:
res = []
for idx in range (len(PARTS),0,-1):
item = PARTS[idx-1]
if 0==len(res) and 'EMPTY:0' == item: continue
res.insert (0, item)
return res
elif 'MSDOS' == PTTYPE:
return PARTS[0:4]
#/**
# ogListLogicalPartitions int_ndisk
#@brief Metafunción que lista las particiones lógicas de una tabla tipo MSDOS.
#@param int_ndisk nº de orden del disco
#@see ogListPartitions
#*/ ##
def ogListLogicalPartitions (disk):
PTTYPE = ogGetPartitionTableType (disk)
if not PTTYPE: return None
PARTS = ogListPartitions (disk)
if not PARTS: return None
return PARTS[4:]
#/**
# ogLockDisk int_ndisk
#@brief Genera un fichero de bloqueo para un disco en uso exlusivo.
#@param int_ndisk nº de orden del disco
#@return (nada)
#@exception OG_ERR_FORMAT Formato incorrecto.
#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo.
#@note El fichero de bloqueo se localiza en \c /var/lock/disk, siendo \c disk el dispositivo del disco, sustituyendo el carácter "/" por "-".
#*/ ##
def ogLockDisk (disk):
DISK = ogDiskToDev (disk)
if not DISK: return None
open (f'/var/lock/lock{DISK.replace("/", "-")}', 'a').close()
#/**
# ogSetPartitionActive int_ndisk int_npartition
#@brief Establece cual es la partición activa de un disco.
#@param int_ndisk nº de orden del disco
#@param int_npartition nº de orden de la partición
#@return (nada).
#@exception OG_ERR_FORMAT Formato incorrecto.
#@exception OG_ERR_NOTFOUND Disco o partición no corresponden con un dispositivo.
#@note Requisitos: parted
#*/ ##
def ogSetPartitionActive (disk, par):
if InventoryLib.ogIsEfiActive():
SystemLib.ogEcho (['session', 'log'], 'warning', f'EFI: {ogGlobals.lang.MSG_DONTUSE} ogSetPartitionActive')
return
DISK = ogDiskToDev (disk)
if DISK is None: return
PART = ogDiskToDev (disk, par)
if PART is None: return
subprocess.run (["parted", "-s", DISK, "set", par, "boot", "on"])
return
#/**
# ogSetPartitionId int_ndisk int_npartition hex_partid
#@brief Cambia el identificador de la partición.
#@param int_ndisk nº de orden del disco
#@param int_npartition nº de orden de la partición
#@param hex_partid identificador de tipo de partición
#@return (nada)
#@exception OG_ERR_FORMAT Formato incorrecto.
#@exception OG_ERR_NOTFOUND Disco o partición no corresponden con un dispositivo.
#@exception OG_ERR_OUTOFLIMIT Valor no válido.
#@exception OG_ERR_PARTITION Error al cambiar el id. de partición.
#@attention Requisitos: fdisk, sgdisk
#*/ ##
def ogSetPartitionId (disk, par, id):
DISK = ogDiskToDev (disk)
if not DISK: return None
PART = ogDiskToDev (disk, par)
if not PART: return None
# Error si el id. de partición no es hexadecimal.
if not re.match ('^[0-9A-Fa-f]+$', id):
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_OUTOFLIMIT, id)
return None
# Elección del tipo de partición.
PTTYPE = ogGetPartitionTableType (disk)
if 'GPT' == PTTYPE:
p = subprocess.run (['sgdisk', f'-t{par}:{id.upper()}', DISK])
elif 'MSDOS' == PTTYPE:
p = subprocess.run (['sfdisk', '--id', DISK, par, id.upper()])
else:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_OUTOFLIMIT, f'{disk},{PTTYPE}')
return None
# MSDOS) Correcto si fdisk sin error o con error pero realiza Syncing
if 0 == p.returncode:
subprocess.run (['partprobe', DISK])
return True
else:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, f'{disk},{part},{id}')
return None
#/**
# ogSetPartitionSize int_ndisk int_npartition int_size
#@brief Muestra el tamano en KB de una particion determinada.
#@param int_ndisk nº de orden del disco
#@param int_npartition nº de orden de la partición
#@param int_size tamaño de la partición (en KB)
#@return (nada)
#@exception OG_ERR_FORMAT formato incorrecto.
#@exception OG_ERR_NOTFOUND disco o particion no detectado (no es un dispositivo).
#@note Requisitos: sfdisk, awk
#@todo Compruebar que el tamaño sea numérico positivo y evitar que pueda solaparse con la siguiente partición.
#*/ ##
def ogSetPartitionSize (disk, par, size):
DISK = ogDiskToDev (disk)
if not DISK: return None
PART = ogDiskToDev (disk, par)
if not PART: return None
# Convertir tamaño en KB a sectores de 512 B.
SIZE = 2 * int (size)
# Redefinir el tamaño de la partición.
p = subprocess.run (['sfdisk', '-f', '-uS', f'-N{par}', DISK], input=f',{SIZE}', text=True)
if p.returncode:
ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, f'{disk},{par}')
return None
subprocess.run (['partprobe', DISK])
#/**
# ogSetPartitionType int_ndisk int_npartition str_type
#@brief Cambia el identificador de la partición.
#@param int_ndisk nº de orden del disco
#@param int_npartition nº de orden de la partición
#@param str_type mnemónico de tipo de partición
#@return (nada)
#@attention Requisitos: fdisk, sgdisk
#*/ ##
def ogSetPartitionType (disk, par, t):
DISK = ogDiskToDev (disk)
if not DISK: return None
PART = ogDiskToDev (disk, par)
if not PART: return None
PTTYPE = ogGetPartitionTableType (disk)
if not PTTYPE: return None
ID = ogTypeToId (t, PTTYPE)
if not ID:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'{t},{PTTYPE}')
return None
ogSetPartitionId (disk, par, ID)
#/**
# ogTypeToId str_parttype [str_tabletype]
#@brief Devuelve el identificador correspondiente a un tipo de partición.
#@param str_parttype mnemónico de tipo de partición.
#@param str_tabletype mnemónico de tipo de tabla de particiones (MSDOS por defecto).
#@return int_idpart identificador de tipo de partición.
#@exception OG_ERR_FORMAT Formato incorrecto.
#@note tabletype = { MSDOS, GPT }, (MSDOS, por defecto)
#*/ ##
#ogTypeToId ('LINUX') => "83"
#ogTypeToId ('LINUX', 'MSDOS') => "83"
def ogTypeToId (type, pttype='MSDOS'):
data = {
'GPT': {
'EMPTY': '0',
'WINDOWS': '0700',
'NTFS': '0700',
'EXFAT': '0700',
'FAT32': '0700',
'FAT16': '0700',
'FAT12': '0700',
'HNTFS': '0700',
'HFAT32': '0700',
'HFAT16': '0700',
'HFAT12': '0700',
'WIN-RESERV': '0C01',
'CHROMEOS-KRN': '7F00',
'CHROMEOS': '7F01',
'CHROMEOS-RESERV': '7F02',
'LINUX-SWAP': '8200',
'LINUX': '8300',
'EXT2': '8300',
'EXT3': '8300',
'EXT4': '8300',
'REISERFS': '8300',
'REISER4': '8300',
'XFS': '8300',
'JFS': '8300',
'LINUX-RESERV': '8301',
'LINUX-LVM': '8E00',
'FREEBSD-DISK': 'A500',
'FREEBSD-BOOT': 'A501',
'FREEBSD-SWAP': 'A502',
'FREEBSD': 'A503',
'HFS-BOOT': 'AB00',
'HFS': 'AF00',
'HFS+': 'AF00',
'HFSPLUS': 'AF00',
'HFS-RAID': 'AF01',
'SOLARIS-BOOT': 'BE00',
'SOLARIS': 'BF00',
'SOLARIS-SWAP': 'BF02',
'SOLARIS-DISK': 'BF03',
'CACHE': 'CA00',
'EFI': 'EF00',
'LINUX-RAID': 'FD00',
},
'MSDOS': {
'EMPTY': '0',
'FAT12': '1',
'EXTENDED': '5',
'FAT16': '6',
'WINDOWS': '7',
'NTFS': '7',
'EXFAT': '7',
'FAT32': 'b',
'HFAT12': '11',
'HFAT16': '16',
'HNTFS': '17',
'HFAT32': '1b',
'LINUX-SWAP': '82',
'LINUX': '83',
'EXT2': '83',
'EXT3': '83',
'EXT4': '83',
'REISERFS': '83',
'REISER4': '83',
'XFS': '83',
'JFS': '83',
'LINUX-LVM': '8e',
'FREEBSD': 'a5',
'OPENBSD': 'a6',
'HFS': 'af',
'HFS+': 'af',
'SOLARIS-BOOT': 'be',
'SOLARIS': 'bf',
'CACHE': 'ca',
'DATA': 'da',
'GPT': 'ee',
'EFI': 'ef',
'VMFS': 'fb',
'LINUX-RAID': 'fd',
},
'LVM': {
'LVM-LV': '10000',
},
'ZVOL': {
'ZFS-VOL': '10010',
},
}
if pttype.upper() not in data: return None
if type.upper() not in data[pttype.upper()]: return None
return data[pttype.upper()][type.upper()]
#/**
# ogUnhidePartition int_ndisk int_npartition
#@brief Hace visible una partición oculta.
#@param int_ndisk nº de orden del disco
#@param int_npartition nº de orden de la partición
#@return (nada)
#@exception OG_ERR_FORMAT formato incorrecto.
#@exception OG_ERR_NOTFOUND disco o particion no detectado (no es un dispositivo).
#@exception OG_ERR_PARTITION tipo de partición no reconocido.
#*/ ##
def ogUnhidePartition (disk, par):
PART = ogDiskToDev (disk, par)
if not PART: return None
TYPE = ogGetPartitionType (disk, par)
if 'HNTFS' == TYPE: NEWTYPE = 'NTFS'
elif 'HFAT32' == TYPE: NEWTYPE = 'FAT32'
elif 'HFAT16' == TYPE: NEWTYPE = 'FAT16'
elif 'HFAT12' == TYPE: NEWTYPE = 'FAT12'
elif 'WIN-RESERV' == TYPE: NEWTYPE = 'WINDOWS'
else:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, TYPE)
return None
ogSetPartitionType (disk, par, NEWTYPE)
#/**
# ogUnlockDisk int_ndisk
#@brief Elimina el fichero de bloqueo para un disco.
#@param int_ndisk nº de orden del disco
#@return (nada)
#@exception OG_ERR_FORMAT Formato incorrecto.
#@exception OG_ERR_NOTFOUND Disco o particion no corresponden con un dispositivo.
#@note El fichero de bloqueo se localiza en \c /var/lock/disk, siendo \c disk el dispositivo del disco, sustituyendo el carácter "/" por "-".
#*/ ##
def ogUnlockDisk (disk):
DISK = ogDiskToDev (disk)
if not DISK: return None
os.remove (f'/var/lock/lock{DISK.replace("/", "-")}')
#/**
# ogUpdatePartitionTable
#@brief Fuerza al kernel releer la tabla de particiones de los discos duros
#@param no requiere
#@return informacion propia de la herramienta
#@note Requisitos: \c partprobe
#@warning pendiente estructurar la funcion a opengnsys
#*/ ##
def ogUpdatePartitionTable():
for disk in ogDiskToDev():
subprocess.run(["partprobe", disk])