source: client/engine/DiskLib.py @ c2925f1a

ogClonningEnginetest-python-scriptsticket-577ticket-585ticket-693ticket-700
Last change on this file since c2925f1a was c2925f1a, checked in by Antonio Emmanuel Guerrero Silva <aguerrero@…>, 9 months ago

refs #577 Migration library from shell to python3

  • Property mode set to 100644
File size: 43.1 KB
Line 
1import subprocess
2import shutil
3import os
4import subprocess
5
6def parted(*args):
7    parted_path = shutil.which("parted")
8    if parted_path:
9        try:
10            result = subprocess.run(
11                [parted_path] + list(args),
12                timeout=3,
13                capture_output=True,
14                text=True
15            )
16            return result.stdout
17        except subprocess.TimeoutExpired:
18            return "Error: Command 'parted' timed out"
19    else:
20        return "Error: 'parted' command not found"
21
22def ogCreatePartitions(*args):
23    # Variables locales
24    ND = DISK = PTTYPE = PART = SECTORS = START = SIZE = TYPE = CACHEPART = None
25    IODISCO = IOSIZE = CACHESIZE = EXTSTART = EXTSIZE = NVME_PREFIX = tmpsfdisk = None
26
27    # Si se solicita, mostrar ayuda.
28    if len(args) == 1 and args[0] == "help":
29        ogHelp('ogCreatePartitions', 'ogCreatePartitions int_ndisk str_parttype:int_partsize ...',
30               'ogCreatePartitions 1 NTFS:10000000 EXT3:5000000 LINUX-SWAP:1000000')
31        return
32
33    # Error si no se reciben al menos 2 parámetros.
34    if len(args) < 2:
35        ogRaiseError(OG_ERR_FORMAT)
36        return
37
38    # Nº total de sectores, para evitar desbordamiento (evitar redondeo).
39    ND = args[0]
40    DISK = ogDiskToDev(ND)
41    if DISK is None:
42        return
43
44    PTTYPE = ogGetPartitionTableType(ND) or "MSDOS"  # Por defecto para discos vacíos.
45
46    if PTTYPE == "GPT":
47        ogCreateGptPartitions(*args)
48        return
49    elif PTTYPE != "MSDOS":
50        ogRaiseError(OG_ERR_PARTITION, PTTYPE)
51        return
52
53    SECTORS = ogGetLastSector(ND)
54
55    # Se recalcula el nº de sectores del disco 1, si existe partición de caché.
56    CACHEPART = ogFindCache()
57    if CACHEPART and ND == CACHEPART.split()[0]:
58        CACHESIZE = int(ogGetCacheSize()) * 2
59
60    # Sector de inicio (la partición 1 empieza en el sector 63).
61    IODISCO = ogDiskToDev(ND)
62    IOSIZE = subprocess.getoutput(f"fdisk -l {IODISCO} | awk '/I\\/O/ {{print $4}}'")
63
64    if IOSIZE == "4096":
65        START = 4096
66        SECTORS -= 8192
67        if CACHESIZE:
68            SECTORS = SECTORS - CACHESIZE + 2048 - (SECTORS - CACHESIZE) % 2048 - 1
69    else:
70        START = 63
71        if CACHESIZE:
72            SECTORS -= CACHESIZE
73
74    PART = 1
75
76    # Fichero temporal de entrada para "sfdisk"
77    tmpsfdisk = f"/tmp/sfdisk{os.getpid()}"
78    try:
79        with open(tmpsfdisk, 'w') as f:
80            f.write("unit: sectors\n\n")
81
82        NVME_PREFIX = "p" if "nvme" in DISK else ""
83
84        # Generar fichero de entrada para "sfdisk" con las particiones.
85        args = args[1:]  # Shift
86        while args:
87            # Conservar los datos de la partición de caché.
88            if f"{ND} {PART}" == CACHEPART and CACHESIZE:
89                with open(tmpsfdisk, 'a') as f:
90                    f.write(f"{DISK}{NVME_PREFIX}{PART} : start={SECTORS + 1}, size={CACHESIZE}, Id=ca\n")
91                PART += 1
92
93            # Leer formato de cada parámetro - Tipo:Tamaño
94            TYPE = args[0].split(":")[0]
95            SIZE = int(args[0].split(":")[1])
96
97            # Obtener identificador de tipo de partición válido.
98            ID = ogTypeToId(TYPE, "MSDOS")
99            with open(tmpsfdisk, 'a') as f:
100                f.write(f"{DISK}{NVME_PREFIX}{PART} : start={START}, size={SIZE}, Id={ID}\n")
101            START += SIZE
102            SECTORS -= SIZE
103            PART += 1
104            args = args[1:]
105
106        # Ejecutar "sfdisk" con el fichero temporal.
107        subprocess.run(["sfdisk", DISK], input=open(tmpsfdisk, 'r').read(), text=True)
108        subprocess.run(["partprobe", DISK])
109
110    finally:
111        # Eliminar fichero temporal.
112        if os.path.exists(tmpsfdisk):
113            os.remove(tmpsfdisk)
114
115    if CACHESIZE:
116        ogMountCache()
117    return 0
118
119def ogCreateGptPartitions(*args):
120    # Variables locales
121    ND = DISK = PART = SECTORS = ALIGN = START = SIZE = TYPE = CACHEPART = CACHESIZE = DELOPTIONS = OPTIONS = None
122
123    # Si se solicita, mostrar ayuda.
124    if len(args) == 1 and args[0] == "help":
125        ogHelp('ogCreateGptPartitions', 'ogCreateGptPartitions int_ndisk str_parttype:int_partsize ...',
126                'ogCreateGptPartitions 1 NTFS:10000000 EXT3:5000000 LINUX-SWAP:1000000')
127        return
128
129    # Error si no se reciben menos de 2 parámetros.
130    if len(args) < 2:
131        ogRaiseError(OG_ERR_FORMAT)
132        return
133
134    # Nº total de sectores, para evitar desbordamiento (evitar redondeo).
135    ND = args[0]
136    DISK = ogDiskToDev(ND)
137    if DISK is None:
138        return
139
140    # Se calcula el ultimo sector del disco (total de sectores usables)
141    SECTORS = ogGetLastSector(ND)
142
143    # Se recalcula el nº de sectores del disco si existe partición de caché.
144    CACHEPART = ogFindCache()
145    if ND == CACHEPART.split()[0]:
146        CACHESIZE = int(ogGetCacheSize()) * 2
147    if CACHESIZE:
148        SECTORS -= CACHESIZE
149
150    # Si el disco es GPT empieza en el sector 2048  por defecto, pero podria cambiarse
151    ALIGN = subprocess.getoutput(f"sgdisk -D {DISK} 2>/dev/null")
152    START = ALIGN
153    PART = 1
154
155    # Leer parámetros con definición de particionado.
156    args = args[1:]  # Shift
157    while args:
158        # Si PART es la cache, nos la saltamos y seguimos con el siguiente numero para conservar los datos de la partición de caché.
159        if f"{ND} {PART}" == CACHEPART and CACHESIZE:
160            PART += 1
161
162        # Leer formato de cada parámetro - Tipo:Tamaño
163        TYPE = args[0].split(":")[0]
164        SIZE = int(args[0].split(":")[1])
165
166        # Error si la partición es extendida (no válida en discos GPT).
167        if TYPE == "EXTENDED":
168            ogRaiseError(OG_ERR_PARTITION, "EXTENDED")
169            return
170
171        # Comprobar si existe la particion actual, capturamos su tamaño para ver si cambio o no
172        PARTSIZE = ogGetPartitionSize(ND, PART)
173        # En sgdisk no se pueden redimensionar las particiones, es necesario borrarlas y volver a crealas
174        if PARTSIZE:
175            DELOPTIONS += f" -d{PART}"
176
177        # Creamos la particion
178        # Obtener identificador de tipo de partición válido.
179        ID = ogTypeToId(TYPE, "GPT")
180        if TYPE != "CACHE" and ID:
181            OPTIONS += f" -n{PART}:{START}:+{SIZE} -t{PART}:{ID} "
182
183        START += SIZE
184
185        # Error si se supera el nº total de sectores.
186        if START > SECTORS:
187            ogRaiseError(OG_ERR_FORMAT, f"{START//2} > {SECTORS//2}")
188            return
189
190        PART += 1
191        args = args[1:]
192
193    # Desmontar los sistemas de archivos del disco antes de realizar las operaciones.
194    ogUnmountAll(ND)
195    if CACHESIZE:
196        ogUnmountCache()
197
198    # Si la tabla de particiones no es valida, volver a generarla.
199    ogCreatePartitionTable(ND)
200
201    # Definir particiones y notificar al kernel.
202    # Borramos primero las particiones y luego creamos las nuevas
203    subprocess.run(["sgdisk"] + DELOPTIONS.split() + OPTIONS.split() + [DISK], stderr=subprocess.DEVNULL)
204    subprocess.run(["partprobe", DISK], stderr=subprocess.DEVNULL)
205
206    if CACHESIZE:
207        ogMountCache()
208    return 0
209
210def ogCreatePartitionTable(*args):
211    # Variables locales
212    DISK = PTTYPE = CREATE = CREATEPTT = None
213
214    # Si se solicita, mostrar ayuda.
215    if len(args) == 1 and args[0] == "help":
216        ogHelp('ogCreatePartitionTable', 'ogCreatePartitionTable int_ndisk [str_partype]',
217               'ogCreatePartitionTable 1 GPT', 'ogCreatePartitionTable 1')
218        return
219
220    # Error si no se reciben 1 o 2 parámetros.
221    if len(args) == 1:
222        CREATEPTT = ""
223    elif len(args) == 2:
224        CREATEPTT = args[1]
225    else:
226        ogRaiseError(OG_ERR_FORMAT)
227        return
228
229    # Capturamos el tipo de tabla de particiones actual
230    DISK = ogDiskToDev(args[0])
231    if DISK is None:
232        return
233    PTTYPE = ogGetPartitionTableType(args[0]) or "MSDOS"  # Por defecto para discos vacíos.
234    CREATEPTT = CREATEPTT or PTTYPE
235
236    # Si la tabla actual y la que se indica son iguales, se comprueba si hay que regenerarla.
237    if CREATEPTT == PTTYPE:
238        if PTTYPE == "GPT":
239            try:
240                result = subprocess.run(
241                    ["sgdisk", "-p", DISK],
242                    stderr=subprocess.PIPE,
243                    stdout=subprocess.DEVNULL
244                )
245                if result.returncode != 0:
246                    CREATE = "GPT"
247            except subprocess.CalledProcessError:
248                CREATE = "GPT"
249        elif PTTYPE == "MSDOS":
250            try:
251                result = subprocess.run(
252                    ["parted", "-s", DISK, "print"],
253                    stderr=subprocess.PIPE,
254                    stdout=subprocess.DEVNULL
255                )
256                if result.returncode != 0:
257                    CREATE = "MSDOS"
258            except subprocess.CalledProcessError:
259                CREATE = "MSDOS"
260    else:
261        CREATE = CREATEPTT
262
263    # Dependiendo del valor de CREATE, creamos la tabla de particiones en cada caso.
264    if CREATE == "GPT":
265        if PTTYPE == "MSDOS":
266            subprocess.run(["sgdisk", "-go", DISK])
267        else:
268            subprocess.run(["gdisk", DISK], input="2\nw\nY\n", text=True)
269        subprocess.run(["partprobe", DISK], stderr=subprocess.DEVNULL)
270    elif CREATE == "MSDOS":
271        if PTTYPE == "GPT":
272            subprocess.run(["sgdisk", "-Z", DISK])
273        subprocess.run(["fdisk", DISK], input="o\nn\np\n\n\n\nd\n\nw", text=True)
274        subprocess.run(["partprobe", DISK], stderr=subprocess.DEVNULL)
275    return
276
277def ogDeletePartitionTable(*args):
278    # Variables locales
279    DISK = None
280
281    # Si se solicita, mostrar ayuda.
282    if len(args) == 1 and args[0] == "help":
283        ogHelp('ogDeletePartitionTable', 'ogDeletePartitionTable int_ndisk', 'ogDeletePartitionTable 1')
284        return
285
286    # Error si no se reciben 1 parámetros.
287    if len(args) != 1:
288        ogRaiseError(OG_ERR_FORMAT)
289        return
290
291    # Obteniendo Identificador linux del disco.
292    DISK = ogDiskToDev(args[0])
293    if DISK is None:
294        return
295
296    # Crear una tabla de particiones vacía.
297    PTTYPE = ogGetPartitionTableType(args[0])
298    if PTTYPE == "GPT":
299        subprocess.run(["sgdisk", "-o", DISK])
300    elif PTTYPE == "MSDOS":
301        subprocess.run(["fdisk", DISK], input="o\nw", text=True)
302    return
303
304def ogDevToDisk(dev):
305    # Variables locales
306    CACHEFILE = "/var/cache/disks.cfg"
307    PART = None
308    n = 1
309
310    # Si se solicita, mostrar ayuda.
311    if dev == "help":
312        ogHelp("ogDevToDisk", "ogDevToDisk path_device | LABEL=str_label | UUID=str_uuid",
313               "ogDevToDisk /dev/sda  =>  1",
314               "ogDevToDisk /dev/sda1  =>  1 1",
315               "ogDevToDisk LABEL=CACHE  =>  1 4")
316        return
317
318    # Error si no se recibe 1 parámetro.
319    if len(dev) != 1:
320        ogRaiseError(OG_ERR_FORMAT)
321        return
322
323    # Obtener dispositivo a partir de camino, etiqueta o UUID.
324    DEV = dev[0]
325    if DEV.startswith("LABEL="):
326        DEV = subprocess.getoutput(f"blkid -L {DEV[6:]}")
327    elif DEV.startswith("PARTLABEL="):
328        DEV = subprocess.getoutput(f"realpath /dev/disk/by-partlabel/{DEV[11:]} 2>/dev/null")
329    elif DEV.startswith("PARTUUID="):
330        DEV = subprocess.getoutput(f"realpath /dev/disk/by-partuuid/{DEV[10:]} 2>/dev/null")
331    elif DEV.startswith("UUID="):
332        DEV = subprocess.getoutput(f"blkid -U {DEV[5:]}")
333
334    # Error si no es fichero de bloques o directorio (para LVM).
335    if not os.path.exists(DEV):
336        ogRaiseError(OG_ERR_NOTFOUND, dev)
337        return
338
339    # Buscar en fichero de caché de discos.
340    if os.path.exists(CACHEFILE):
341        with open(CACHEFILE, 'r') as f:
342            for line in f:
343                parts = line.strip().split(':')
344                if len(parts) == 2 and parts[1] == DEV:
345                    PART = parts[0]
346                    break
347
348    if PART:
349        return PART
350
351    # Si no se encuentra, procesa todos los discos para devolver su nº de orden y de partición.
352    disks = ogDiskToDev()
353    for d in disks:
354        NVME_PREFIX = "p" if "nvme" in d else ""
355        if DEV.startswith(d):
356            return f"{n} {DEV[len(d) + len(NVME_PREFIX):]}"
357        n += 1
358
359    ogRaiseError(OG_ERR_NOTFOUND, dev)
360    return OG_ERR_NOTFOUND
361
362def ogDiskToDev(*args):
363    # Variables locales
364    CACHEFILE = "/var/cache/disks.cfg"
365    ALLDISKS = []
366    MPATH = VOLGROUPS = ZFSVOLS = DISK = PART = ZPOOL = None
367    i = 1
368
369    # Si se solicita, mostrar ayuda.
370    if len(args) == 1 and args[0] == "help":
371        ogHelp('ogDiskToDev', 'ogDiskToDev int_ndisk [int_npartition]',
372               'ogDiskToDev      =>  /dev/sda /dev/sdb',
373               'ogDiskToDev 1    =>  /dev/sda',
374               'ogDiskToDev 1 1  =>  /dev/sda1')
375        return
376
377    # Borrar fichero de caché de configuración si hay cambios en las particiones.
378    if not filecmp.cmp('/proc/partitions', '/tmp/.partitions'):
379        # Guardar copia de las particiones definidas para comprobar cambios.
380        shutil.copy2('/proc/partitions', '/tmp/.partitions')
381        os.remove(CACHEFILE)
382
383    # Si existe una correspondencia con disco/dispositivo en el caché; mostrarlo y salir.
384    with open(CACHEFILE, 'r') as f:
385        for line in f:
386            parts = line.strip().split(':')
387            if len(parts) == 2 and parts[0] == ":".join(args):
388                print(parts[1])
389                return
390
391    # Continuar para detectar nuevos dispositivos.
392    # Listar dispositivos de discos.
393    all_disks = subprocess.getoutput("lsblk -n -e 1,2 -x MAJ:MIN 2>/dev/null || lsblk -n -e 1,2").splitlines()
394    for line in all_disks:
395        parts = line.split()
396        if parts[5] == "disk":
397            ALLDISKS.append(f"/dev/{parts[0]}")
398
399    # Listar volúmenes lógicos.
400    VOLGROUPS = subprocess.getoutput("vgs -a --noheadings 2>/dev/null").splitlines()
401    VOLGROUPS = [f"/dev/{line.split()[0]}" for line in VOLGROUPS]
402
403    # Detectar caminos múltiples (ignorar mensaje si no está configurado Multipath).
404    try:
405        MPATH = subprocess.getoutput("multipath -l -v 1 2>/dev/null").splitlines()
406        MPATH = [f"/dev/mapper/{line.split()[0]}" for line in MPATH]
407        # Quitar de la lista los discos que forman parte de Multipath.
408        for line in subprocess.getoutput("multipath -ll").splitlines():
409            if line.split()[5] == "ready":
410                disk = f"/dev/{line.split()[2]}"
411                if disk in ALLDISKS:
412                    ALLDISKS.remove(disk)
413    except subprocess.CalledProcessError:
414        MPATH = []
415
416    # Detectar volúmenes ZFS.
417    ZFSVOLS = subprocess.getoutput("blkid").splitlines()
418    ZFSVOLS = [line.split(":")[0] for line in ZFSVOLS if "zfs" in line]
419
420    # Mostrar salidas segun el número de parametros.
421    if len(args) == 0:
422        print(" ".join(ALLDISKS))
423    elif len(args) == 1:
424        # Error si el parámetro no es un número positivo.
425        if not args[0].isdigit() or int(args[0]) <= 0:
426            ogRaiseError(OG_ERR_FORMAT, args[0])
427            return
428        disk = ALLDISKS[int(args[0])-1]
429        # Error si el fichero no existe.
430        if not os.path.exists(disk):
431            ogRaiseError(OG_ERR_NOTFOUND, args[0])
432            return
433        # Actualizar caché de configuración y mostrar dispositivo.
434        with open(CACHEFILE, 'a') as f:
435            f.write(f"{args[0]}:{disk}\n")
436        print(disk)
437    elif len(args) == 2:
438        # Error si los 2 parámetros no son números positivos.
439        if not args[0].isdigit() or int(args[0]) <= 0 or not args[1].isdigit() or int(args[1]) <= 0:
440            ogRaiseError(OG_ERR_FORMAT, f"{args[0]} {args[1]}")
441            return
442        disk = ALLDISKS[int(args[0])-1]
443        # Error si el fichero no existe.
444        if not os.path.exists(disk):
445            ogRaiseError(OG_ERR_NOTFOUND, args[0])
446            return
447        part = f"{disk}{args[1]}"
448        # Comprobar si es partición.
449        if os.path.exists(part):
450            # Actualizar caché de configuración y mostrar dispositivo.
451            with open(CACHEFILE, 'a') as f:
452                f.write(f"{args[0]} {args[1]}:{part}\n")
453            print(part)
454        else:
455            # Comprobar si RAID o Multipath (tener en cuenta enlace simbólico).
456            part = f"{disk}p{args[1]}"
457            if os.path.exists(part) and os.stat(part, follow_symlinks=True).st_mode[0] == "b":
458                # Actualizar caché de configuración y mostrar dispositivo.
459                with open(CACHEFILE, 'a') as f:
460                    f.write(f"{args[0]} {args[1]}:{part}\n")
461                print(part)
462            else:
463                part = ""
464                # Comprobar si volumen lógico.
465                if disk in VOLGROUPS:
466                    lvscan = subprocess.getoutput("lvscan -a 2>/dev/null").splitlines()
467                    for line in lvscan:
468                        parts = line.split("'")
469                        if parts[1].startswith(f"{disk}/") and i == int(args[1]):
470                            part = parts[1]
471                            break
472                        i += 1
473                # Comprobar si volumen ZFS que puede ser montado.
474                if disk in ZFSVOLS:
475                    subprocess.run(["zpool", "import", "-f", "-R", "/mnt", "-N", "-a"], stderr=subprocess.DEVNULL)
476                    zpool = subprocess.getoutput(f"blkid -s LABEL -o value {disk}")
477                    zfs_list = subprocess.getoutput(f"zfs list -Hp -o name,canmount,mountpoint -r {zpool}").splitlines()
478                    for line in zfs_list:
479                        parts = line.split()
480                        if parts[1] == "on" and parts[2] != "none":
481                            if i == int(args[1]):
482                                part = parts[0]
483                                break
484                            i += 1
485                # Salir si no se encuentra dispositivo.
486                if not part:
487                    ogRaiseError(OG_ERR_NOTFOUND, f"{args[0]} {args[1]}")
488                    return
489                # Devolver camino al dispositivo.
490                # Actualizar caché de configuración y mostrar dispositivo.
491                with open(CACHEFILE, 'a') as f:
492                    f.write(f"{args[0]} {args[1]}:{part}\n")
493                print(part)
494    else:
495        ogRaiseError(OG_ERR_FORMAT)
496        return
497
498def ogGetDiskSize(*args):
499    # Variables locales
500    DISK = SIZE = None
501
502    # Si se solicita, mostrar ayuda.
503    if len(args) == 1 and args[0] == "help":
504        ogHelp('ogGetDiskSize', 'ogGetDiskSize int_ndisk', 'ogGetDiskSize 1  => 244198584')
505        return
506
507    # Error si no se recibe 1 parámetro.
508    if len(args) != 1:
509        ogRaiseError(OG_ERR_FORMAT)
510        return
511
512    # Obtener el tamaño del disco.
513    DISK = ogDiskToDev(args[0])
514    if DISK is None:
515        return
516    SIZE = subprocess.getoutput(f"lsblk -n -b -o SIZE {DISK}")
517
518    # Mostrar salida.
519    if SIZE:
520        print(SIZE)
521    return
522
523def ogGetDiskType(*args):
524    # Variables locales
525    DEV = MAJOR = TYPE = None
526
527    # Si se solicita, mostrar ayuda.
528    if len(args) == 1 and args[0] == "help":
529        ogHelp('ogGetDiskType', 'ogGetDiskType path_device', 'ogGetDiskType /dev/sdb  =>  USB')
530        return
531
532    # Error si no se recibe 1 parámetro.
533    if len(args) != 1:
534        ogRaiseError(OG_ERR_FORMAT)
535        return
536
537    # Obtener el driver del dispositivo de bloques.
538    DEV = args[0].split("/dev/")[1]
539    MAJOR = subprocess.getoutput(f"awk -v D='{DEV}' '{{if ($4==D) print $1;}}' /proc/partitions")
540    TYPE = subprocess.getoutput(f"awk -v D={MAJOR} '/Block/ {{bl=1}} {{if ($1==D&&bl) print toupper($2)}}' /proc/devices")
541    # Devolver mnemónico del driver de dispositivo.
542    if TYPE == "SD":
543        TYPE = "DISK"
544        if subprocess.getoutput(f"udevadm info -q property {args[0]} 2>/dev/null | grep -q '^ID_BUS=usb'"):
545            TYPE = "USB"
546    elif TYPE == "BLKEXT":
547        TYPE = "NVM"
548    elif TYPE == "SR" or TYPE.startswith("IDE"):
549        TYPE = "CDROM"  # FIXME Comprobar discos IDE.
550    elif TYPE == "MD" or TYPE.startswith("CCISS"):
551        TYPE = "RAID"
552    elif TYPE == "DEVICE-MAPPER":
553        TYPE = "MAPPER"  # FIXME Comprobar LVM y RAID.
554    print(TYPE)
555    return
556
557def ogGetEsp():
558
559    for d in subprocess.getoutput("blkid -o device").split():
560        # Previene error para /dev/loop0
561        PART = ogDevToDisk([d])
562        # En discos NVMe blkid devuelve una salida del tipo:
563        #    >/dev/loop0
564        #    >/dev/nvme0n1
565        #    >/dev/nvme0n1p1
566        # al analizar la particion nvme0n1, PART solo tiene un argumento y hace que ogGetPartitionId lance un error
567        LEN = len(PART)
568        if LEN > 1:
569            if ogGetPartitionId(PART) == ogTypeToId("EFI", "GPT"):
570                return PART
571    return None
572
573def ogGetLastSector(*args):
574    # Variables locales
575    DISK = None
576    PART = None
577    LASTSECTOR = None
578
579    # Si se solicita, mostrar ayuda.
580    if len(args) == 1 and args[0] == "help":
581        ogHelp("ogGetLastSector", "ogGetLastSector int_ndisk [int_npart]",
582               "ogGetLastSector 1  =>  488392064",
583               "ogGetLastSector 1 1  =>  102400062")
584        return
585
586    # Obtener último sector.
587    if len(args) == 1:  # Para un disco.
588        DISK = ogDiskToDev(args[0])
589        if DISK is None:
590            return
591        LASTSECTOR = subprocess.getoutput(f"sgdisk -p {DISK} | awk '/last usable sector/ {{print($(NF))}}'")
592    elif len(args) == 2:  # Para una partición.
593        DISK = ogDiskToDev(args[0])
594        if DISK is None:
595            return
596        PART = ogDiskToDev(args[0], args[1])
597        if PART is None:
598            return
599        LASTSECTOR = subprocess.getoutput(f"sgdisk -p {DISK} | awk -v P='{args[1]}' '{{if ($1==P) print $3}}'")
600    else:  # Error si se reciben más parámetros.
601        ogRaiseError(OG_ERR_FORMAT)
602        return
603
604    print(LASTSECTOR)
605    return
606
607def ogGetPartitionActive(*args):
608    # Variables locales
609    DISK = None
610
611    # Si se solicita, mostrar ayuda.
612    if len(args) == 1 and args[0] == "help":
613        ogHelp('ogGetPartitionActive', 'ogGetPartitionActive int_ndisk', 'ogGetPartitionActive 1  =>  1')
614        return
615
616    # Error si no se recibe 1 parámetro.
617    if len(args) != 1:
618        ogRaiseError(OG_ERR_FORMAT)
619        return
620
621    # Comprobar que el disco existe y listar su partición activa.
622    DISK = ogDiskToDev(args[0])
623    if DISK is None:
624        return
625    output = subprocess.getoutput(f"parted -sm {DISK} print 2>/dev/null | awk -F: '$7~/boot/ {{print $1}}'")
626    print(output)
627    return
628
629def ogGetPartitionId(*args):
630    # Variables locales
631    DISK = None
632    ID = None
633
634    # Si se solicita, mostrar ayuda.
635    if len(args) == 1 and args[0] == "help":
636        ogHelp('ogGetPartitionId', 'ogGetPartitionId int_ndisk int_npartition', 'ogGetPartitionId 1 1  =>  7')
637        return
638
639    # Error si no se reciben 2 parámetros.
640    if len(args) != 2:
641        ogRaiseError(OG_ERR_FORMAT)
642        return
643
644    # Detectar y mostrar el id. de tipo de partición.
645    DISK = ogDiskToDev(args[0])
646    if DISK is None:
647        return
648    PTTYPE = ogGetPartitionTableType(args[0])
649    if PTTYPE == "GPT":
650        ID = subprocess.getoutput(f"sgdisk -p {DISK} 2>/dev/null | awk -v p={args[1]} '{{if ($1==p) print $6;}}'")
651        if ID == "8300" and f"{args[0]} {args[1]}" == ogFindCache():
652            ID = "CA00"
653    elif PTTYPE == "MSDOS":
654        ID = subprocess.getoutput(f"sfdisk --id {DISK} {args[1]} 2>/dev/null")
655    elif PTTYPE == "LVM":
656        ID = "10000"
657    elif PTTYPE == "ZPOOL":
658        ID = "10010"
659
660    print(ID)
661    return
662
663def ogGetPartitionSize(*args):
664    # Variables locales
665    PART = None
666    SIZE = None
667
668    # Si se solicita, mostrar ayuda.
669    if len(args) == 1 and args[0] == "help":
670        ogHelp('ogGetPartitionSize', 'ogGetPartitionSize int_ndisk int_npartition', 'ogGetPartitionSize 1 1  =>  10000000')
671        return
672
673    # Error si no se reciben 2 parámetros.
674    if len(args) != 2:
675        ogRaiseError(OG_ERR_FORMAT)
676        return
677
678    # Devolver tamaño de partición, del volumen lógico o del sistema de archivos (para ZFS).
679    PART = ogDiskToDev(args[0], args[1])
680    if PART is None:
681        return
682    SIZE = subprocess.getoutput(f"partx -gbo SIZE {PART} 2>/dev/null | awk '{{print int($1/1024)}}'")
683    if not SIZE:
684        SIZE = subprocess.getoutput(f"lvs --noheadings -o lv_size --units k {PART} | awk '{{printf \"%d\",$0}}'")
685    if not SIZE:
686        SIZE = ogGetFsSize(args[0], args[1])
687    print(SIZE or 0)
688    return
689
690def ogGetPartitionsNumber(*args):
691    # Variables locales
692    DISK = None
693
694    # Si se solicita, mostrar ayuda.
695    if len(args) == 1 and args[0] == "help":
696        ogHelp('ogGetPartitionsNumber', 'ogGetPartitionsNumber int_ndisk', 'ogGetPartitionsNumber 1  =>  3')
697        return
698
699    # Error si no se recibe 1 parámetro.
700    if len(args) != 1:
701        ogRaiseError(OG_ERR_FORMAT)
702        return
703
704    # Contar el número de veces que aparece el disco en su lista de particiones.
705    DISK = ogDiskToDev(args[0])
706    if DISK is None:
707        return
708    PTTYPE = ogGetPartitionTableType(args[0])
709    if PTTYPE in ["GPT", "MSDOS"]:
710        output = subprocess.getoutput(f"partx -gso NR {DISK} 2>/dev/null | awk -v p=0 '{{p=$1}} END {{print p}}'")
711    elif PTTYPE == "LVM":
712        output = subprocess.getoutput(f"lvs --noheadings {DISK} 2>/dev/null | wc -l")
713    elif PTTYPE == "ZPOOL":
714        subprocess.run(["zpool", "list"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)  # Check if zpool command exists
715        subprocess.run(["modprobe", "zfs"])  # Load zfs module if not already loaded
716        subprocess.run(["zpool", "import", "-f", "-R", "/mnt", "-N", "-a"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)  # Import all zpools
717        output = subprocess.getoutput(f"zfs list -Hp -o name,canmount,mountpoint -r $(blkid -s LABEL -o value {DISK}) | awk '$2==\"on\" && $3!=\"none\" {{c++}} END {{print c}}'")
718    else:
719        output = None
720
721    print(output)
722    return
723
724def ogGetPartitionTableType(*args):
725    # Variables locales
726    DISK = None
727    TYPE = None
728
729    # Si se solicita, mostrar ayuda.
730    if len(args) == 1 and args[0] == "help":
731        ogHelp('ogGetPartitionTableType', 'ogGetPartitionTableType int_ndisk', 'ogGetPartitionTableType 1  =>  MSDOS')
732        return
733
734    # Error si no se recibe 1 parámetro.
735    if len(args) != 1:
736        ogRaiseError(OG_ERR_FORMAT)
737        return
738
739    # Sustituye n de disco por su dispositivo.
740    DISK = ogDiskToDev(args[0])
741    if DISK is None:
742        return
743
744    # Comprobar tabla de particiones.
745    if os.path.exists(DISK):
746        output = subprocess.getoutput(f"parted -sm {DISK} print 2>/dev/null | awk -F: -v D={DISK} '{{ if($1 == D) print toupper($6)}}'")
747        if not output:
748            output = subprocess.getoutput(f"parted -sm {DISK} print 2>/dev/null | awk -F: -v D={DISK} '{{ if($1 == D) print toupper($6)}}'")
749    # Comprobar si es volumen lógico.
750    if os.path.isdir(DISK) and subprocess.run(["vgs", DISK], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0:
751        output = "LVM"
752    # Comprobar si es pool de ZFS.
753    if not output or output == "UNKNOWN":
754        blkid_output = subprocess.getoutput(f"blkid -s TYPE {DISK} | grep zfs")
755        if blkid_output:
756            output = "ZPOOL"
757
758    # Mostrar salida.
759    if output:
760        print(output)
761    return
762
763def ogGetPartitionType(*args):
764    # Variables locales
765    ID = None
766    TYPE = None
767
768    # Si se solicita, mostrar ayuda.
769    if len(args) == 1 and args[0] == "help":
770        ogHelp('ogGetPartitionType', 'ogGetPartitionType int_ndisk int_npartition', 'ogGetPartitionType 1 1  =>  NTFS')
771        return
772
773    # Error si no se reciben 2 parámetros.
774    if len(args) != 2:
775        ogRaiseError(OG_ERR_FORMAT)
776        return
777
778    # Detectar id. de tipo de partición y codificar al mnemónico.
779    ID = ogGetPartitionId(args[0], args[1])
780    if ID is None:
781        return
782    TYPE = ogIdToType(ID)
783    print(TYPE)
784    return
785
786def ogHidePartition(*args):
787    # Variables locales
788    PART = None
789    TYPE = None
790    NEWTYPE = None
791
792    # Si se solicita, mostrar ayuda.
793    if len(args) == 1 and args[0] == "help":
794        ogHelp('ogHidePartition', 'ogHidePartition int_ndisk int_npartition', 'ogHidePartition 1 1')
795        return
796
797    # Error si no se reciben 2 parámetros.
798    if len(args) != 2:
799        ogRaiseError(OG_ERR_FORMAT)
800        return
801
802    # Obtener el dispositivo de la partición.
803    PART = ogDiskToDev(args[0], args[1])
804    if PART is None:
805        return
806
807    # Obtener tipo de partición.
808    TYPE = ogGetPartitionType(args[0], args[1])
809    if TYPE == "NTFS":
810        NEWTYPE = "HNTFS"
811    elif TYPE == "FAT32":
812        NEWTYPE = "HFAT32"
813    elif TYPE == "FAT16":
814        NEWTYPE = "HFAT16"
815    elif TYPE == "FAT12":
816        NEWTYPE = "HFAT12"
817    elif TYPE == "WINDOWS":
818        NEWTYPE = "WIN-RESERV"
819    else:
820        ogRaiseError(OG_ERR_PARTITION, TYPE)
821        return
822
823    # Cambiar tipo de partición.
824    ogSetPartitionType(args[0], args[1], NEWTYPE)
825    return
826
827def ogIdToType(ID):
828    # Obtener valor hexadecimal de 4 caracteres rellenado con 0 por delante.
829    ID = ID.zfill(4)
830    TYPE = None
831
832    # Asignar el tipo de partición según el ID.
833    if ID == "0000":
834        TYPE = "EMPTY"
835    elif ID == "0001":
836        TYPE = "FAT12"
837    elif ID in ["0005", "000f"]:
838        TYPE = "EXTENDED"
839    elif ID in ["0006", "000e"]:
840        TYPE = "FAT16"
841    elif ID == "0007":
842        TYPE = "NTFS"
843    elif ID in ["000b", "000c"]:
844        TYPE = "FAT32"
845    elif ID == "0011":
846        TYPE = "HFAT12"
847    elif ID == "0012":
848        TYPE = "COMPAQDIAG"
849    elif ID in ["0016", "001e"]:
850        TYPE = "HFAT16"
851    elif ID == "0017":
852        TYPE = "HNTFS"
853    elif ID in ["001b", "001c"]:
854        TYPE = "HFAT32"
855    elif ID == "0042":
856        TYPE = "WIN-DYNAMIC"
857    elif ID in ["0082", "8200"]:
858        TYPE = "LINUX-SWAP"
859    elif ID in ["0083", "8300"]:
860        TYPE = "LINUX"
861    elif ID in ["008e", "8E00"]:
862        TYPE = "LINUX-LVM"
863    elif ID in ["00a5", "a503"]:
864        TYPE = "FREEBSD"
865    elif ID == "00a6":
866        TYPE = "OPENBSD"
867    elif ID == "00a7":
868        TYPE = "CACHE"  # (compatibilidad con Brutalix)
869    elif ID in ["00af", "af00"]:
870        TYPE = "HFS"
871    elif ID in ["00be", "be00"]:
872        TYPE = "SOLARIS-BOOT"
873    elif ID in ["00bf", "bf00145"]:
874        TYPE = "SOLARIS"
875    elif ID in ["00ca", "ca00"]:
876        TYPE = "CACHE"
877    elif ID == "00da":
878        TYPE = "DATA"
879    elif ID == "00ee":
880        TYPE = "GPT"
881    elif ID in ["00ef", "ef00"]:
882        TYPE = "EFI"
883    elif ID == "00fb":
884        TYPE = "VMFS"
885    elif ID in ["00fd", "fd00"]:
886        TYPE = "LINUX-RAID"
887    elif ID == "0700":
888        TYPE = "WINDOWS"
889    elif ID == "0c01":
890        TYPE = "WIN-RESERV"
891    elif ID == "7f00":
892        TYPE = "CHROMEOS-KRN"
893    elif ID == "7f01":
894        TYPE = "CHROMEOS"
895    elif ID == "7f02":
896        TYPE = "CHROMEOS-RESERV"
897    elif ID == "8301":
898        TYPE = "LINUX-RESERV"
899    elif ID == "a500":
900        TYPE = "FREEBSD-DISK"
901    elif ID == "a501":
902        TYPE = "FREEBSD-BOOT"
903    elif ID == "a502":
904        TYPE = "FREEBSD-SWAP"
905    elif ID == "ab00":
906        TYPE = "HFS-BOOT"
907    elif ID == "af01":
908        TYPE = "HFS-RAID"
909    elif ID == "bf02":
910        TYPE = "SOLARIS-SWAP"
911    elif ID == "bf03":
912        TYPE = "SOLARIS-DISK"
913    elif ID == "ef01":
914        TYPE = "MBR"
915    elif ID == "ef02":
916        TYPE = "BIOS-BOOT"
917    elif ID == "10000":
918        TYPE = "LVM-LV"
919    elif ID == "10010":
920        TYPE = "ZFS-VOL"
921    else:
922        TYPE = "UNKNOWN"
923
924    return TYPE
925
926def ogIsDiskLocked(*args):
927    # Variables locales
928    DISK = None
929    LOCKFILE = None
930
931    # Si se solicita, mostrar ayuda.
932    if len(args) == 1 and args[0] == "help":
933        ogHelp('ogIsDiskLocked', 'ogIsDiskLocked int_ndisk', 'if ogIsDiskLocked(1): ...')
934        return
935
936    # Falso, en caso de error.
937    if len(args) != 1:
938        return False
939    DISK = ogDiskToDev(args[0], 2)
940    if DISK is None:
941        return False
942
943    # Comprobar existencia de fichero de bloqueo para el disco.
944    LOCKFILE = f"/var/lock/lock{DISK.replace('/', '-')}"
945    return os.path.isfile(LOCKFILE)
946
947def ogListPartitions(*args):
948    # Variables locales
949    DISK = None
950    PART = None
951    NPARTS = None
952    TYPE = None
953    SIZE = None
954
955    # Si se solicita, mostrar ayuda.
956    if len(args) == 1 and args[0] == "help":
957        ogHelp('ogListPartitions', 'ogListPartitions int_ndisk', 'ogListPartitions 1  =>  NTFS:10000000 EXT3:5000000 LINUX-SWAP:1000000')
958        return
959
960    # Error si no se recibe 1 parámetro.
961    if len(args) != 1:
962        ogRaiseError(OG_ERR_FORMAT)
963        return
964
965    # Procesar la salida de parted.
966    DISK = ogDiskToDev(args[0])
967    if DISK is None:
968        return
969    NPARTS = ogGetPartitionsNumber(args[0])
970    for PART in range(1, NPARTS + 1):
971        TYPE = ogGetPartitionType(args[0], PART) or "EMPTY"
972        SIZE = ogGetPartitionSize(args[0], PART) or 0
973        print(f"{TYPE}:{SIZE} ", end="")
974    print()
975    return
976
977def ogListPrimaryPartitions():
978    # Variables locales
979    PTTYPE = None
980    PARTS = None
981
982    # Si se solicita, mostrar ayuda.
983    if len(args) == 1 and args[0] == "help":
984        ogHelp('ogListPrimaryPartitions', 'ogListPrimaryPartitions int_ndisk', 'ogListPrimaryPartitions 1  =>  NTFS:10000000 EXT3:5000000 EXTENDED:1000000')
985        return
986
987    PTTYPE = ogGetPartitionTableType(args[0])
988    if PTTYPE is None:
989        return
990    PARTS = ogListPartitions(*args)
991    if PARTS is None:
992        return
993
994    if PTTYPE == "GPT":
995        print(PARTS.rstrip(" EMPTY:0"))
996    elif PTTYPE == "MSDOS":
997        print(PARTS.split(" ")[0:4])
998    return
999
1000def ogListLogicalPartitions(*args):
1001    # Variables locales
1002    PTTYPE = None
1003    PARTS = None
1004
1005    # Si se solicita, mostrar ayuda.
1006    if len(args) == 1 and args[0] == "help":
1007        ogHelp('ogListLogicalPartitions', 'ogListLogicalPartitions int_ndisk', 'ogListLogicalPartitions 1  =>  LINUX-SWAP:999998')
1008        return
1009
1010    PTTYPE = ogGetPartitionTableType(args[0])
1011    if PTTYPE is None:
1012        return
1013    PARTS = ogListPartitions(*args)
1014    if PARTS is None:
1015        return
1016
1017    return PARTS.split(" ")[4:]
1018
1019def ogLockDisk(*args):
1020    # Variables locales
1021    DISK = None
1022    LOCKFILE = None
1023
1024    # Si se solicita, mostrar ayuda.
1025    if len(args) == 1 and args[0] == "help":
1026        ogHelp('ogLockDisk', 'ogLockDisk int_ndisk', 'ogLockDisk 1')
1027        return
1028
1029    # Error si no se recibe 1 parámetro.
1030    if len(args) != 1:
1031        ogRaiseError(OG_ERR_FORMAT)
1032        return
1033
1034    # Obtener partición.
1035    DISK = ogDiskToDev(args[0])
1036    if DISK is None:
1037        return
1038
1039    # Crear archivo de bloqueo exclusivo.
1040    LOCKFILE = f"/var/lock/lock{DISK.replace('/', '-')}"
1041    open(LOCKFILE, 'a').close()
1042
1043def ogSetPartitionActive(*args):
1044    # Variables locales
1045    DISK = None
1046    PART = None
1047
1048    # Si se solicita, mostrar ayuda.
1049    if len(args) == 1 and args[0] == "help":
1050        ogHelp('ogSetPartitionActive', 'ogSetPartitionActive int_ndisk int_npartition', 'ogSetPartitionActive 1 1')
1051        return
1052
1053    # Error si no se reciben 2 parámetros.
1054    if len(args) != 2:
1055        ogRaiseError(OG_ERR_FORMAT)
1056        return
1057
1058    # Comprobar que el disco existe y activar la partición indicada.
1059    DISK = ogDiskToDev(args[0])
1060    if DISK is None:
1061        return
1062    PART = ogDiskToDev(args[0], args[1])
1063    if PART is None:
1064        return
1065    subprocess.run(["parted", "-s", DISK, "set", args[1], "boot", "on"], stderr=subprocess.DEVNULL)
1066    return
1067
1068def ogSetPartitionId(*args):
1069    # Variables locales
1070    DISK = None
1071    PART = None
1072    PTTYPE = None
1073    ID = None
1074
1075    # Si se solicita, mostrar ayuda.
1076    if len(args) == 1 and args[0] == "help":
1077        ogHelp('ogSetPartitionId', 'ogSetPartitionId int_ndisk int_npartition hex_partid', 'ogSetPartitionId 1 1 7')
1078        return
1079
1080    # Error si no se reciben 3 parámetros.
1081    if len(args) != 3:
1082        ogRaiseError(OG_ERR_FORMAT)
1083        return
1084
1085    # Sustituye nº de disco y nº partición por su dispositivo.
1086    DISK = ogDiskToDev(args[0])
1087    if DISK is None:
1088        return
1089    PART = ogDiskToDev(args[0], args[1])
1090    if PART is None:
1091        return
1092    # Error si el id. de partición no es hexadecimal.
1093    ID = args[2].upper()
1094    if not re.match("^[0-9A-F]+$", ID):
1095        ogRaiseError(OG_ERR_OUTOFLIMIT, args[2])
1096        return
1097
1098    # Elección del tipo de partición.
1099    PTTYPE = ogGetPartitionTableType(args[0])
1100    if PTTYPE == "GPT":
1101        subprocess.run(["sgdisk", f"-t{args[1]}:{ID}", DISK], stderr=subprocess.DEVNULL)
1102    elif PTTYPE == "MSDOS":
1103        subprocess.run(["sfdisk", f"--id", DISK, args[1], ID], stderr=subprocess.DEVNULL)
1104    else:
1105        ogRaiseError(OG_ERR_OUTOFLIMIT, f"{args[0]},{PTTYPE}")
1106        return
1107
1108    # MSDOS) Correcto si fdisk sin error o con error pero realiza Syncing
1109    if subprocess.run(["partprobe", DISK], stderr=subprocess.DEVNULL).returncode == 0:
1110        return
1111    else:
1112        ogRaiseError(OG_ERR_PARTITION, f"{args[0]},{args[1]},{args[2]}")
1113        return
1114
1115def ogSetPartitionSize(*args):
1116    # Variables locales
1117    DISK = None
1118    PART = None
1119    SIZE = None
1120
1121    # Si se solicita, mostrar ayuda.
1122    if len(args) == 1 and args[0] == "help":
1123        ogHelp('ogSetPartitionSize', 'ogSetPartitionSize int_ndisk int_npartition int_size', 'ogSetPartitionSize 1 1 10000000')
1124        return
1125
1126    # Error si no se reciben 3 parámetros.
1127    if len(args) != 3:
1128        ogRaiseError(OG_ERR_FORMAT)
1129        return
1130
1131    # Obtener el tamaño de la partición.
1132    DISK = ogDiskToDev(args[0])
1133    if DISK is None:
1134        return
1135    PART = ogDiskToDev(args[0], args[1])
1136    if PART is None:
1137        return
1138    # Convertir tamaño en KB a sectores de 512 B.
1139    SIZE = int(args[2]) * 2
1140    # Redefinir el tamaño de la partición.
1141    subprocess.run(["sfdisk", "-f", "-uS", f"-N{args[1]}", DISK], input=f",{SIZE}", text=True, stderr=subprocess.DEVNULL)
1142    subprocess.run(["partprobe", DISK], stderr=subprocess.DEVNULL)
1143    return
1144
1145def ogSetPartitionType(*args):
1146    # Variables locales
1147    DISK = None
1148    PART = None
1149    PTTYPE = None
1150    TYPE = None
1151
1152    # Si se solicita, mostrar ayuda.
1153    if len(args) == 1 and args[0] == "help":
1154        ogHelp('ogSetPartitionType', 'ogSetPartitionType int_ndisk int_npartition str_type', 'ogSetPartitionType 1 1 NTFS')
1155        return
1156
1157    # Error si no se reciben 3 parámetros.
1158    if len(args) != 3:
1159        ogRaiseError(OG_ERR_FORMAT)
1160        return
1161
1162    # Sustituye nº de disco por su dispositivo.
1163    DISK = ogDiskToDev(args[0])
1164    if DISK is None:
1165        return
1166    PART = ogDiskToDev(args[0], args[1])
1167    if PART is None:
1168        return
1169
1170    # Elección del tipo de partición.
1171    PTTYPE = ogGetPartitionTableType(args[0])
1172    if PTTYPE is None:
1173        return
1174    TYPE = args[2]
1175    ID = ogTypeToId(TYPE, PTTYPE)
1176    if ID is None:
1177        ogRaiseError(OG_ERR_FORMAT, f"{TYPE},{PTTYPE}")
1178        return
1179
1180    ogSetPartitionId(args[0], args[1], ID)
1181    return
1182
1183def ogTypeToId(TYPE, PTTYPE="MSDOS"):
1184    # Asociar id. de partición para su mnemónico.
1185    ID = ""
1186
1187    # Elección del tipo de partición.
1188    if PTTYPE == "GPT":
1189        if TYPE == "EMPTY":
1190            ID = "0"
1191        elif TYPE in ["WINDOWS", "NTFS", "EXFAT", "FAT32", "FAT16", "FAT12", "HNTFS", "HFAT32", "HFAT16", "HFAT12"]:
1192            ID = "0700"
1193        elif TYPE == "WIN-RESERV":
1194            ID = "0C01"
1195        elif TYPE == "CHROMEOS-KRN":
1196            ID = "7F00"
1197        elif TYPE == "CHROMEOS":
1198            ID = "7F01"
1199        elif TYPE == "CHROMEOS-RESERV":
1200            ID = "7F02"
1201        elif TYPE == "LINUX-SWAP":
1202            ID = "8200"
1203        elif TYPE in ["LINUX", "EXT2", "EXT3", "EXT4", "REISERFS", "REISER4", "XFS", "JFS"]:
1204            ID = "8300"
1205        elif TYPE == "LINUX-RESERV":
1206            ID = "8301"
1207        elif TYPE == "LINUX-LVM":
1208            ID = "8E00"
1209        elif TYPE == "FREEBSD-DISK":
1210            ID = "A500"
1211        elif TYPE == "FREEBSD-BOOT":
1212            ID = "A501"
1213        elif TYPE == "FREEBSD-SWAP":
1214            ID = "A502"
1215        elif TYPE == "FREEBSD":
1216            ID = "A503"
1217        elif TYPE == "HFS-BOOT":
1218            ID = "AB00"
1219        elif TYPE in ["HFS", "HFS+"]:
1220            ID = "AF00"
1221        elif TYPE == "HFS-RAID":
1222            ID = "AF01"
1223        elif TYPE == "SOLARIS-BOOT":
1224            ID = "BE00"
1225        elif TYPE == "SOLARIS":
1226            ID = "BF00"
1227        elif TYPE == "SOLARIS-SWAP":
1228            ID = "BF02"
1229        elif TYPE == "SOLARIS-DISK":
1230            ID = "BF03"
1231        elif TYPE == "CACHE":
1232            ID = "CA00"
1233        elif TYPE == "EFI":
1234            ID = "EF00"
1235        elif TYPE == "LINUX-RAID":
1236            ID = "FD00"
1237    elif PTTYPE == "MSDOS":
1238        if TYPE == "EMPTY":
1239            ID = "0"
1240        elif TYPE == "FAT12":
1241            ID = "1"
1242        elif TYPE == "EXTENDED":
1243            ID = "5"
1244        elif TYPE == "FAT16":
1245            ID = "6"
1246        elif TYPE in ["WINDOWS", "NTFS", "EXFAT"]:
1247            ID = "7"
1248        elif TYPE == "FAT32":
1249            ID = "b"
1250        elif TYPE == "HFAT12":
1251            ID = "11"
1252        elif TYPE == "HFAT16":
1253            ID = "16"
1254        elif TYPE == "HNTFS":
1255            ID = "17"
1256        elif TYPE == "HFAT32":
1257            ID = "1b"
1258        elif TYPE == "LINUX-SWAP":
1259            ID = "82"
1260        elif TYPE in ["LINUX", "EXT2", "EXT3", "EXT4", "REISERFS", "REISER4", "XFS", "JFS"]:
1261            ID = "83"
1262        elif TYPE == "LINUX-LVM":
1263            ID = "8e"
1264        elif TYPE == "FREEBSD":
1265            ID = "a5"
1266        elif TYPE == "OPENBSD":
1267            ID = "a6"
1268        elif TYPE in ["HFS", "HFS+"]:
1269            ID = "af"
1270        elif TYPE == "SOLARIS-BOOT":
1271            ID = "be"
1272        elif TYPE == "SOLARIS":
1273            ID = "bf"
1274        elif TYPE == "CACHE":
1275            ID = "ca"
1276        elif TYPE == "DATA":
1277            ID = "da"
1278        elif TYPE == "GPT":
1279            ID = "ee"
1280        elif TYPE == "EFI":
1281            ID = "ef"
1282        elif TYPE == "VMFS":
1283            ID = "fb"
1284        elif TYPE == "LINUX-RAID":
1285            ID = "fd"
1286    elif PTTYPE == "LVM":
1287        if TYPE == "LVM-LV":
1288            ID = "10000"
1289    elif PTTYPE == "ZVOL":
1290        if TYPE == "ZFS-VOL":
1291            ID = "10010"
1292
1293    return ID
1294
1295def ogUnhidePartition(*args):
1296    # Variables locales
1297    PART = None
1298    TYPE = None
1299    NEWTYPE = None
1300
1301    # Si se solicita, mostrar ayuda.
1302    if len(args) == 1 and args[0] == "help":
1303        ogHelp('ogUnhidePartition', 'ogUnhidePartition int_ndisk int_npartition', 'ogUnhidePartition 1 1')
1304        return
1305
1306    # Error si no se reciben 2 parámetros.
1307    if len(args) != 2:
1308        ogRaiseError(OG_ERR_FORMAT)
1309        return
1310
1311    PART = ogDiskToDev(args[0], args[1])
1312    if PART is None:
1313        return
1314
1315    # Obtener tipo de partición.
1316    TYPE = ogGetPartitionType(args[0], args[1])
1317    if TYPE == "HNTFS":
1318        NEWTYPE = "NTFS"
1319    elif TYPE == "HFAT32":
1320        NEWTYPE = "FAT32"
1321    elif TYPE == "HFAT16":
1322        NEWTYPE = "FAT16"
1323    elif TYPE == "HFAT12":
1324        NEWTYPE = "FAT12"
1325    elif TYPE == "WIN-RESERV":
1326        NEWTYPE = "WINDOWS"
1327    else:
1328        ogRaiseError(OG_ERR_PARTITION, TYPE)
1329        return
1330
1331    # Cambiar tipo de partición.
1332    ogSetPartitionType(args[0], args[1], NEWTYPE)
1333    return
1334
1335def ogUnlockDisk(*args):
1336    # Variables locales
1337    DISK = None
1338    LOCKFILE = None
1339
1340    # Si se solicita, mostrar ayuda.
1341    if len(args) == 1 and args[0] == "help":
1342        ogHelp('ogUnlockDisk', 'ogUnlockDisk int_ndisk', 'ogUnlockDisk 1')
1343        return
1344
1345    # Error si no se recibe 1 parámetro.
1346    if len(args) != 1:
1347        ogRaiseError(OG_ERR_FORMAT)
1348        return
1349
1350    # Obtener partición.
1351    DISK = ogDiskToDev(args[0])
1352    if DISK is None:
1353        return
1354
1355    # Borrar archivo de bloqueo exclusivo.
1356    LOCKFILE = f"/var/lock/lock{DISK.replace('/', '-')}"
1357    os.remove(LOCKFILE)
1358    return
1359
1360def ogUpdatePartitionTable():
1361    for disk in ogDiskToDev():
1362        subprocess.run(["partprobe", disk])
Note: See TracBrowser for help on using the repository browser.