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

1427 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(*args):
# Variables locales
ND = DISK = PTTYPE = PART = SECTORS = START = SIZE = TYPE = CACHEPART = None
IODISCO = IOSIZE = CACHESIZE = EXTSTART = EXTSIZE = NVME_PREFIX = tmpsfdisk = None
# Si se solicita, mostrar ayuda.
if len(args) == 1 and args[0] == "help":
SystemLib.ogHelp('ogCreatePartitions', 'ogCreatePartitions int_ndisk str_parttype:int_partsize ...',
'ogCreatePartitions 1 NTFS:10000000 EXT3:5000000 LINUX-SWAP:1000000')
return
# Error si no se reciben al menos 2 parámetros.
if len(args) < 2:
SystemLib.ogRaiseError(OG_ERR_FORMAT)
return
# Nº total de sectores, para evitar desbordamiento (evitar redondeo).
ND = args[0]
DISK = ogDiskToDev(ND)
if DISK is None:
return
PTTYPE = ogGetPartitionTableType(ND) or "MSDOS" # Por defecto para discos vacíos.
if PTTYPE == "GPT":
ogCreateGptPartitions(*args)
return
elif PTTYPE != "MSDOS":
SystemLib.ogRaiseError(OG_ERR_PARTITION, PTTYPE)
return
SECTORS = ogGetLastSector(ND)
# Se recalcula el nº de sectores del disco 1, si existe partición de caché.
CACHEPART = CacheLib.ogFindCache()
if CACHEPART and ND == CACHEPART.split()[0]:
CACHESIZE = int(CacheLib.ogGetCacheSize()) * 2
# Sector de inicio (la partición 1 empieza en el sector 63).
IODISCO = ogDiskToDev(ND)
IOSIZE = subprocess.getoutput(f"fdisk -l {IODISCO} | awk '/I\\/O/ {{print $4}}'")
if IOSIZE == "4096":
START = 4096
SECTORS -= 8192
if CACHESIZE:
SECTORS = SECTORS - CACHESIZE + 2048 - (SECTORS - CACHESIZE) % 2048 - 1
else:
START = 63
if CACHESIZE:
SECTORS -= CACHESIZE
PART = 1
# Fichero temporal de entrada para "sfdisk"
tmpsfdisk = f"/tmp/sfdisk{os.getpid()}"
try:
with open(tmpsfdisk, 'w') as f:
f.write("unit: sectors\n\n")
NVME_PREFIX = "p" if "nvme" in DISK else ""
# Generar fichero de entrada para "sfdisk" con las particiones.
args = args[1:] # Shift
while args:
# Conservar los datos de la partición de caché.
if f"{ND} {PART}" == CACHEPART and CACHESIZE:
with open(tmpsfdisk, 'a') as f:
f.write(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 = args[0].split(":")[0]
SIZE = int(args[0].split(":")[1])
# Obtener identificador de tipo de partición válido.
ID = ogTypeToId(TYPE, "MSDOS")
with open(tmpsfdisk, 'a') as f:
f.write(f"{DISK}{NVME_PREFIX}{PART} : start={START}, size={SIZE}, Id={ID}\n")
START += SIZE
SECTORS -= SIZE
PART += 1
args = args[1:]
# Ejecutar "sfdisk" con el fichero temporal.
subprocess.run(["sfdisk", DISK], input=open(tmpsfdisk, 'r').read(), text=True)
subprocess.run(["partprobe", DISK])
finally:
# Eliminar fichero temporal.
if os.path.exists(tmpsfdisk):
os.remove(tmpsfdisk)
if CACHESIZE:
CacheLib.ogMountCache()
return 0
#/**
# 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(*args):
# Variables locales
ND = DISK = PART = SECTORS = ALIGN = START = SIZE = TYPE = CACHEPART = CACHESIZE = DELOPTIONS = OPTIONS = None
# Si se solicita, mostrar ayuda.
if len(args) == 1 and args[0] == "help":
SystemLib.ogHelp('ogCreateGptPartitions', 'ogCreateGptPartitions int_ndisk str_parttype:int_partsize ...',
'ogCreateGptPartitions 1 NTFS:10000000 EXT3:5000000 LINUX-SWAP:1000000')
return
# Error si no se reciben menos de 2 parámetros.
if len(args) < 2:
SystemLib.ogRaiseError(OG_ERR_FORMAT)
return
# Nº total de sectores, para evitar desbordamiento (evitar redondeo).
ND = args[0]
DISK = ogDiskToDev(ND)
if DISK is None:
return
# Se calcula el ultimo sector del disco (total de sectores usables)
SECTORS = ogGetLastSector(ND)
# Se recalcula el nº de sectores del disco si existe partición de caché.
CACHEPART = CacheLib.ogFindCache()
if ND == CACHEPART.split()[0]:
CACHESIZE = int(ogGetCacheSize()) * 2
if CACHESIZE:
SECTORS -= CACHESIZE
# Si el disco es GPT empieza en el sector 2048 por defecto, pero podria cambiarse
ALIGN = subprocess.getoutput(f"sgdisk -D {DISK} 2>/dev/null")
START = ALIGN
PART = 1
# Leer parámetros con definición de particionado.
args = args[1:] # Shift
while args:
# Si PART es la cache, nos la saltamos y seguimos con el siguiente numero para 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 = args[0].split(":")[0]
SIZE = int(args[0].split(":")[1])
# Error si la partición es extendida (no válida en discos GPT).
if TYPE == "EXTENDED":
SystemLib.ogRaiseError(OG_ERR_PARTITION, "EXTENDED")
return
# 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 += f" -d{PART}"
# Creamos la particion
# Obtener identificador de tipo de partición válido.
ID = ogTypeToId(TYPE, "GPT")
if TYPE != "CACHE" and ID:
OPTIONS += f" -n{PART}:{START}:+{SIZE} -t{PART}:{ID} "
START += SIZE
# Error si se supera el nº total de sectores.
if START > SECTORS:
SystemLib.ogRaiseError(OG_ERR_FORMAT, f"{START//2} > {SECTORS//2}")
return
PART += 1
args = args[1:]
# Desmontar los sistemas de archivos del disco antes de realizar las operaciones.
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.
# Borramos primero las particiones y luego creamos las nuevas
subprocess.run(["sgdisk"] + DELOPTIONS.split() + OPTIONS.split() + [DISK], stderr=subprocess.DEVNULL)
subprocess.run(["partprobe", DISK], stderr=subprocess.DEVNULL)
if CACHESIZE:
CacheLib.ogMountCache()
return 0
#/**
# 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])
if result.returncode:
CREATE = 'GPT'
except subprocess.CalledProcessError:
CREATE = 'GPT'
elif 'MSDOS' == pttype:
try:
result = subprocess.run (['parted', '-s', DISK, 'print'])
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(*args):
# Variables locales
DISK = None
PART = None
SIZE = None
# Si se solicita, mostrar ayuda.
if len(args) == 1 and args[0] == "help":
SystemLib.ogHelp('ogSetPartitionSize', 'ogSetPartitionSize int_ndisk int_npartition int_size', 'ogSetPartitionSize 1 1 10000000')
return
# Error si no se reciben 3 parámetros.
if len(args) != 3:
SystemLib.ogRaiseError(OG_ERR_FORMAT)
return
# Obtener el tamaño de la partición.
DISK = ogDiskToDev(args[0])
if DISK is None:
return
PART = ogDiskToDev(args[0], args[1])
if PART is None:
return
# Convertir tamaño en KB a sectores de 512 B.
SIZE = int(args[2]) * 2
# Redefinir el tamaño de la partición.
subprocess.run(["sfdisk", "-f", "-uS", f"-N{args[1]}", DISK], input=f",{SIZE}", text=True, stderr=subprocess.DEVNULL)
subprocess.run(["partprobe", DISK], stderr=subprocess.DEVNULL)
return
#/**
# 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(*args):
# Variables locales
DISK = None
PART = None
PTTYPE = None
TYPE = None
# Si se solicita, mostrar ayuda.
if len(args) == 1 and args[0] == "help":
SystemLib.ogHelp('ogSetPartitionType', 'ogSetPartitionType int_ndisk int_npartition str_type', 'ogSetPartitionType 1 1 NTFS')
return
# Error si no se reciben 3 parámetros.
if len(args) != 3:
SystemLib.ogRaiseError(OG_ERR_FORMAT)
return
# Sustituye nº de disco por su dispositivo.
DISK = ogDiskToDev(args[0])
if DISK is None:
return
PART = ogDiskToDev(args[0], args[1])
if PART is None:
return
# Elección del tipo de partición.
PTTYPE = ogGetPartitionTableType(args[0])
if PTTYPE is None:
return
TYPE = args[2]
ID = ogTypeToId(TYPE, PTTYPE)
if ID is None:
SystemLib.ogRaiseError(OG_ERR_FORMAT, f"{TYPE},{PTTYPE}")
return
ogSetPartitionId(args[0], args[1], ID)
return
#/**
# 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])