Plan de particionado: GPT o MBR, UEFI o BIOS y alineación a 1 MiB
Calcula la tabla de particiones de un disco como un instalador: sectores alineados a 1 MiB, la última partición con el resto del disco, extendida y lógicas en MBR, y los avisos de UEFI, BIOS con GPT, el límite de 2 TiB de MBR o la falta de raíz. GB frente a GiB.
- GPT y MBR
- UEFI, BIOS y la partición EFI
- Sectores y alineación a 1 MiB
- GB frente a GiB
- Particiones primarias, extendida y lógicas
- Validación de un plan
Enunciado
Al instalar un sistema operativo hay que decidir la tabla de particiones (GPT, la moderna, o MBR, la antigua) según el firmware (UEFI o BIOS) y repartir el disco. Los instaladores alinean cada partición a 1 MiB (2048 sectores de 512 bytes), porque así coincide con los bloques internos de los SSD y de los discos de sector de 4 KiB, y el rendimiento no se resiente.
Además, los fabricantes venden los discos en GB (10⁹ bytes) y los sistemas muestran GiB (2³⁰ bytes): un disco de 500 GB tiene 465,66 GiB, y no falta nada.
Qué tiene que hacer el programa
DISCO n unidad,TABLA GPT|MBR,ARRANQUE UEFI|BIOSy una líneaPARTICION nombre n unidadpor partición (unidades MB, GB y TB decimales, y MiB, GiB y TiB binarias, en mayúsculas o minúsculas); la última puede serPARTICION nombre RESTO. Si una línea no se entiende:Línea N: no se entiende «…»; si falta DISCO, TABLA o ARRANQUE:Faltan DISCO, TABLA o ARRANQUE. Con errores no se escribe nada más.- Primera línea:
Disco de T (S sectores de 512 bytes), tabla X, arranque Y, donde T es el tamaño en la mayor unidad binaria que no dé menos de 1, con dos decimales y coma (465,66 GiB). - La primera partición empieza en el byte 1 MiB (sector 2048). Cada tamaño se redondea hacia arriba a MiB enteros, y cada partición empieza donde acaba la anterior. GPT reserva el último MiB del disco para su copia de la tabla, y el espacio utilizable se redondea hacia abajo a MiB enteros.
RESTOtoma todo lo que queda; solo puede ir una vez y en la última (si no:Error: RESTO solo puede usarse una vez y en la última partición). - Con MBR y más de 4 particiones, las 3 primeras son primarias (1-3), la 4.ª es la extendida que las contiene y las demás son lógicas, numeradas desde el 5; cada lógica empieza 1 MiB más tarde que el final de la anterior (su EBR).
- Si una partición no cabe:
Error: nombre no cabe: quedan T(y no se escribe la tabla, pero sí los avisos). Si todo cabe, la tabla: cabeceraNº Partición Inicio Fin Tamañoy una fila por partición con el número (3 columnas), el nombre (16), el sector de inicio (13), el de fin (13) y el tamaño; despuésSin asignar: T(o0). - Avisos, en este orden, como
Aviso: …: MBR en un disco de más de 2 TiB; UEFI sin/boot/efi; BIOS con GPT sinbios_grub; falta/;/boot/efide menos de 100 MiB; MBR con más de 4 particiones. Si no hay ninguno:Plan correcto.
Entrada
DISCO 500 GB, TABLA GPT, ARRANQUE UEFI y una línea PARTICION nombre tamaño unidad (o RESTO) por partición.
Ejemplos de ejecución
Tu programa debe escribir exactamente esta salida para estas entradas. Las pruebas del editor incluyen estos ejemplos y otros casos ocultos.
Un portátil con UEFI y GPT
Entrada
DISCO 500 GB TABLA GPT ARRANQUE UEFI PARTICION /boot/efi 512 MiB PARTICION swap 8 GiB PARTICION / 60 GiB PARTICION /home RESTO
Salida por consola
Disco de 465,66 GiB (976562500 sectores de 512 bytes), tabla GPT, arranque UEFI Nº Partición Inicio Fin Tamaño 1 /boot/efi 2048 1050623 512,00 MiB 2 swap 1050624 17827839 8,00 GiB 3 / 17827840 143656959 60,00 GiB 4 /home 143656960 976560127 397,16 GiB Sin asignar: 0 Plan correcto
Un equipo antiguo con BIOS y MBR
Entrada
DISCO 120 GiB TABLA MBR ARRANQUE BIOS PARTICION /boot 1 GiB PARTICION / 40 GiB PARTICION swap 4 GiB PARTICION /var 20 GiB PARTICION /home 30 GiB
Salida por consola
Disco de 120,00 GiB (251658240 sectores de 512 bytes), tabla MBR, arranque BIOS Nº Partición Inicio Fin Tamaño 1 /boot 2048 2099199 1,00 GiB 2 / 2099200 85985279 40,00 GiB 3 swap 85985280 94373887 4,00 GiB 5 /var 94375936 136318975 20,00 GiB 6 /home 136321024 199235583 30,00 GiB Sin asignar: 25,00 GiB Aviso: MBR admite 4 particiones primarias: la 4.ª será extendida y las 2 últimas, lógicas
Guía paso a paso
Intenta resolverlo por tu cuenta y abre un paso solo cuando te atasques: cada uno te acerca a la solución sin dártela entera.
1. Todo en bytes
Convierte cada tamaño a bytes con un diccionario de unidades. Trabajar en bytes y pasar a sectores (÷512) solo al escribir evita errores de redondeo.
2. Redondear a MiB
Hacia arriba para el tamaño de cada partición y hacia abajo para el final del espacio útil. Un truco para redondear hacia arriba con enteros: -(-t // MIB) * MIB.
3. Recorrer las particiones
Lleva una variable inicio en bytes que empieza en 1 MiB y avanza con cada partición. Antes de colocar una, comprueba que cabe hasta el final útil.
4. Los avisos
Son comprobaciones independientes sobre la lista de nombres y la configuración: guárdalos en una lista y escríbelos al final.
Resuélvelo aquí
El editor trae el esqueleto del programa. Pulsa «Ejecutar» para comprobarlo con los ejemplos y con 3 casos ocultos que buscan los errores típicos.
Ejemplo
DISCO 500 GB TABLA GPT ARRANQUE UEFI PARTICION /boot/efi 512 MiB PARTICION swap 8 GiB PARTICION / 60 GiB PARTICION /home RESTO
Disco de 465,66 GiB (976562500 sectores de 512 bytes), tabla GPT, arranque UEFI Nº Partición Inicio Fin Tamaño 1 /boot/efi 2048 1050623 512,00 MiB 2 swap 1050624 17827839 8,00 GiB 3 / 17827840 143656959 60,00 GiB 4 /home 143656960 976560127 397,16 GiB Sin asignar: 0 Plan correcto
Solución explicada
Ver la solución completa
1import re
2import sys
3
4MIB = 1024 * 1024
5SECTOR = 512
6UNIDADES = {"MIB": MIB, "GIB": 1024 * MIB, "TIB": 1024 * 1024 * MIB, "MB": 10 ** 6, "GB": 10 ** 9, "TB": 10 ** 12}
7
8
9def tam(bytes_):
10 """Tamaño legible en binario con dos decimales y coma: 59,99 GiB."""
11 for unidad, valor in [("TiB", UNIDADES["TIB"]), ("GiB", UNIDADES["GIB"]), ("MiB", MIB)]:
12 if bytes_ >= valor:
13 return f"{bytes_ / valor:.2f}".replace(".", ",") + " " + unidad
14 return f"{bytes_} B"
15
16
17def main():
18 disco = None
19 tabla = arranque = None
20 particiones = []
21 errores = []
22 for n, linea in enumerate(sys.stdin.read().split("\n"), start=1):
23 p = linea.split()
24 if not p:
25 continue
26 clave = p[0].upper()
27 if clave == "DISCO" and len(p) == 3 and re.fullmatch(r"\d+", p[1]) and p[2].upper() in UNIDADES:
28 disco = int(p[1]) * UNIDADES[p[2].upper()]
29 elif clave == "TABLA" and len(p) == 2 and p[1].upper() in ("GPT", "MBR"):
30 tabla = p[1].upper()
31 elif clave == "ARRANQUE" and len(p) == 2 and p[1].upper() in ("UEFI", "BIOS"):
32 arranque = p[1].upper()
33 elif clave == "PARTICION" and len(p) == 3 and p[2].upper() == "RESTO":
34 particiones.append((p[1], None))
35 elif clave == "PARTICION" and len(p) == 4 and re.fullmatch(r"\d+", p[2]) and p[3].upper() in UNIDADES:
36 particiones.append((p[1], int(p[2]) * UNIDADES[p[3].upper()]))
37 else:
38 errores.append(f"Línea {n}: no se entiende «{linea.strip()}»")
39 if disco is None or tabla is None or arranque is None:
40 errores.append("Faltan DISCO, TABLA o ARRANQUE")
41 for e in errores:
42 print(e)
43 if errores:
44 return
45 print(f"Disco de {tam(disco)} ({disco // SECTOR} sectores de {SECTOR} bytes), tabla {tabla}, arranque {arranque}")
46 avisos = []
47 if tabla == "MBR" and disco > 2 * UNIDADES["TIB"]:
48 avisos.append("MBR solo direcciona 2 TiB: el resto del disco no se podría usar; usa GPT")
49 puntos = [nombre for nombre, _ in particiones]
50 if arranque == "UEFI" and "/boot/efi" not in puntos:
51 avisos.append("Con UEFI hace falta una partición de sistema EFI (/boot/efi, FAT32, de al menos 100 MiB)")
52 if arranque == "BIOS" and tabla == "GPT" and "bios_grub" not in puntos:
53 avisos.append("Con BIOS y GPT, GRUB necesita una pequeña partición bios_grub (1 MiB)")
54 if "/" not in puntos:
55 avisos.append("No hay partición raíz /")
56 efi = [t for nombre, t in particiones if nombre == "/boot/efi"]
57 if efi and efi[0] is not None and efi[0] < 100 * MIB:
58 avisos.append("La partición EFI debería tener al menos 100 MiB")
59 resto = [i for i, (_, t) in enumerate(particiones) if t is None]
60 if len(resto) > 1 or (resto and resto[0] != len(particiones) - 1):
61 print("Error: RESTO solo puede usarse una vez y en la última partición")
62 return
63 # alineación a 1 MiB: la primera empieza en el sector 2048 y GPT reserva su copia en el último MiB
64 inicio = MIB
65 fin_util = disco - (MIB if tabla == "GPT" else 0)
66 fin_util -= fin_util % MIB
67 if tabla == "MBR" and len(particiones) > 4:
68 avisos.append(f"MBR admite 4 particiones primarias: la 4.ª será extendida y las {len(particiones) - 3} últimas, lógicas")
69 filas = []
70 cabe = True
71 for i, (nombre, t) in enumerate(particiones):
72 if tabla == "MBR" and len(particiones) > 4 and i >= 3:
73 inicio += MIB # cada lógica empieza con su EBR, un MiB por alineación
74 tamano = (fin_util - inicio) if t is None else -(-t // MIB) * MIB
75 if tamano <= 0 or inicio + tamano > fin_util:
76 print(f"Error: {nombre} no cabe: quedan {tam(max(0, fin_util - inicio))}")
77 cabe = False
78 break
79 numero = i + 1 if not (tabla == "MBR" and len(particiones) > 4 and i >= 3) else i + 2
80 filas.append((numero, nombre, inicio // SECTOR, (inicio + tamano) // SECTOR - 1, tamano))
81 inicio += tamano
82 if cabe:
83 print("Nº Partición Inicio Fin Tamaño")
84 for numero, nombre, ini, fin, tamano in filas:
85 print(f"{numero:<3} {nombre:<16} {ini:<13} {fin:<13} {tam(tamano)}")
86 libre = fin_util - inicio
87 print(f"Sin asignar: {tam(libre) if libre else '0'}")
88 for a in avisos:
89 print(f"Aviso: {a}")
90 if cabe and not avisos:
91 print("Plan correcto")
92
93
94main()GPT guarda dos copias de la tabla (al principio y al final del disco), admite 128 particiones y discos de zettabytes. MBR solo cabe en el primer sector: 4 entradas y direcciones de 32 bits de sector, es decir, 2 TiB con sectores de 512 bytes.
UEFI arranca leyendo ficheros de una partición FAT32 (la ESP, montada en /boot/efi); BIOS ejecuta el código del primer sector. Por eso GRUB, con BIOS y GPT, necesita un pequeño hueco propio (bios_grub) donde guardar el código que en MBR iría entre la tabla y la primera partición.
Alinear a 1 MiB desperdicia como mucho un MiB por partición y evita que una escritura de 4 KiB toque dos bloques físicos del SSD, que la convertiría en dos lecturas y dos escrituras.
La partición extendida de MBR es un contenedor: no tiene sistema de ficheros y dentro van las lógicas, encadenadas con un registro (EBR) delante de cada una.
Para ir más allá
- Añade el tipo de sistema de ficheros de cada partición y avisa si /boot/efi no es FAT32.
- Calcula también el tamaño recomendado de la swap según la RAM (con y sin hibernación).
- Genera las órdenes de
sgdiskopartedque crearían ese plan.