import subprocess from engine.DiskLib import * from engine.FileLib import * from engine.NetLib import * def ogCreateImageSyntax(*args): FUNCNAME=ogCreateImageSyntax.__name__ # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} path_device path_imagefile [str_tool] [str_compressionlevel]", f"{FUNCNAME} /dev/sda1 /opt/opengnsys/images/prueba.img partclone lzop", f"{FUNCNAME} /dev/sda1 /opt/opengnsys/images/prueba.img") return # Error si no se reciben entre 2 y 4 parámetros. if not (2 <= len(args) <= 4): ogRaiseError(OG_ERR_FORMAT, " ".join(args)) return # Asignación de parámetros. DEV = args[0] IMGFILE = args[1] if len(args) == 2: # Sintaxis por defecto OG DEV IMGFILE TOOL = "partclone" LEVEL = "gzip" elif len(args) == 4: # Sintaxis condicionada. TOOL = args[2].lower() LEVEL = args[3].lower() if TOOL == "ntfsclone": PARAM1 = f"ntfsclone --force --save-image -O - {DEV}" elif TOOL in ["partimage", "default"]: PARAM1 = f"partimage -M -f3 -o -d -B gui=no -c -z0 --volume=0 save {DEV} stdout" elif TOOL == "partclone": FS = ogGetFsType(ogDevToDisk(DEV)) if FS == "EXT[234]": PARAM1 = "partclone.extfs" elif FS == "BTRFS": PARAM1 = "partclone.btrfs" elif FS == "REISERFS": PARAM1 = "partclone.reiserfs" elif FS == "REISER4": PARAM1 = "partclone.reiser4" elif FS == "JFS": PARAM1 = "partclone.jfs" elif FS == "XFS": PARAM1 = "partclone.xfs" elif FS == "F2FS": PARAM1 = "partclone.f2fs" elif FS == "NILFS2": PARAM1 = "partclone.nilfs2" elif FS == "NTFS": PARAM1 = "partclone.ntfs" elif FS == "EXFAT": PARAM1 = "partclone.exfat" elif FS in ["FAT16", "FAT32"]: PARAM1 = "partclone.fat" elif FS in ["HFS", "HFSPLUS"]: PARAM1 = "partclone.hfsp" elif FS == "UFS": PARAM1 = "partclone.ufs" elif FS == "VMFS": PARAM1 = "partclone.vmfs" else: PARAM1 = "partclone.imager" # Por compatibilidad, si no existe el ejecutable usar por defecto "parclone.dd". if not subprocess.run(["which", PARAM1], capture_output=True).returncode: PARAM1 = "partclone.dd" PARAM1 = f"{PARAM1} -d0 -F -c -s {DEV}" # Algunas versiones de partclone.dd no tienen opción "-c". if "-c" not in subprocess.run([PARAM1.split()[0], "--help"], capture_output=True).stdout.decode(): PARAM1 = PARAM1.replace(" -c ", " ") # Comprobar que existe mbuffer. if not subprocess.run(["which", "mbuffer"], capture_output=True).returncode: PARAM2 = "| mbuffer -q -m 40M " else: PARAM2 = " " # Nivel de compresion. if LEVEL in ["0", "none"]: PARAM3 = " > " elif LEVEL in ["1", "lzop"]: PARAM3 = " | lzop > " elif LEVEL in ["2", "gzip"]: PARAM3 = " | gzip -c > " elif LEVEL in ["3", "bzip"]: PARAM3 = " | bzip -c > " # Sintaxis final. if PARAM1: return f"{PARAM1} {PARAM2} {PARAM3} {IMGFILE}" return ogCreateImageSyntax def ogRestoreImageSyntax(*args): FUNCNAME=ogRestoreImageSyntax.__name__ TOOL = "" COMPRESSOR = "" LEVEL = "" PART = "" IMGFILE = "" FILEHEAD = "" INFOIMG = "" # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} filename partition [tool] [levelcompresor]", f"{FUNCNAME} /opt/opengnsys/images/prueba.img /dev/sda1 [partclone] [lzop]") return # Error si no se reciben entre 2 y 4 parámetros. if not (2 <= len(args) <= 4): ogRaiseError(OG_ERR_FORMAT, " ".join(args)) return # controlamos que el parametro 1 (imagen) es tipo file. if not os.path.isfile(args[0]): ogRaiseError(OG_ERR_NOTFOUND, args[0]) return # Si 2 parametros (file-origen-, device-destino-) = ogGetImageFull($1) if len(args) == 2: IMGFILE = args[0] PART = args[1] INFOIMG = ogGetImageInfo(IMGFILE) if INFOIMG: TOOL = INFOIMG.split(":")[0] COMPRESSOR = INFOIMG.split(":")[1] return ogRestoreImageSyntax(IMGFILE, PART, TOOL, COMPRESSOR) # Si cuatro parametros genera sintaxis if len(args) == 4: IMGFILE = args[0] PART = args[1] # comprobamos parametro herramienta compresion. TOOL = args[2].lower() # comprobar parámetro compresor. LEVEL = args[3].lower() if LEVEL in ["0", "none"]: COMPRESSOR = " " elif LEVEL in ["1", "lzop"]: COMPRESSOR = " lzop -dc " elif LEVEL in ["2", "gzip"]: COMPRESSOR = " gzip -dc " elif LEVEL in ["3", "bzip"]: COMPRESSOR = " bzip -dc " else: ogRaiseError(OG_ERR_NOTFOUND, f"Compressor no valid {TOOL}") return # comprobar mbuffer if shutil.which("mbuffer"): MBUFFER = "| mbuffer -q -m 40M " else: MBUFFER = " " if TOOL == "ntfsclone": TOOL = f"| ntfsclone --restore-image --overwrite {PART} -" elif TOOL == "partimage": TOOL = f"| partimage -f3 -B gui=no restore {PART} stdin" elif TOOL.startswith("partclone"): TOOL = f"| partclone.restore -d0 -C -I -o {PART}" elif TOOL == "dd": TOOL = f"| pv | dd conv=sync,noerror bs=1M of={PART}" else: ogRaiseError(OG_ERR_NOTFOUND, f"Tools imaging no valid {TOOL}") return return f"{COMPRESSOR} {IMGFILE} {MBUFFER} {TOOL}" def ogCreateDiskImage(*args): FUNCNAME = ogCreateDiskImage.__name__ # Variables locales DISK = "" PROGRAM = "" IMGDIR = "" IMGFILE = "" IMGTYPE = "" ERRCODE = "" # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} int_ndisk str_repo path_image", f"{FUNCNAME} 1 REPO /disk1") return # Error si no se reciben entre 3 y 5 parámetros. if not (3 <= len(args) <= 5): ogRaiseError(OG_ERR_FORMAT, " ".join(args)) return # Comprobar que no está bloqueada ni la partición, ni la imagen. DISK = ogDiskToDev(args[0]) if ogIsDiskLocked(args[0]): ogRaiseError(OG_ERR_LOCKED, f"{MSG_LOCKED} {args[0]}") return IMGTYPE = "dsk" # Extensión genérica de imágenes de disco. IMGDIR = ogGetParentPath(args[1], args[2]) if not IMGDIR: ogRaiseError(OG_ERR_NOTFOUND, f"{args[1]} {os.path.dirname(args[2])}") return IMGFILE = f"{IMGDIR}/{os.path.basename(args[2])}.{IMGTYPE}" if ogIsImageLocked(IMGFILE): ogRaiseError(OG_ERR_LOCKED, f"{MSG_IMAGE} {args[2]}, {args[3]}") return # No guardar imagen en el propio disco (disco no incluido en el camino del repositorio). if ogGetPath(args[1], "/").startswith(DISK): ogRaiseError(OG_ERR_IMAGE, f"{args[1]} = {DISK}") return # Generar la instruccion a ejecutar antes de aplicar los bloqueos. PROGRAM = ogCreateImageSyntax(DISK, IMGFILE) # Desmontar todos los sistemas de archivos del disco, bloquear disco e imagen. ogUnmountAll(args[0]) ogLockDisk(args[0]) ogLockImage(args[1], f"{args[2]}.{IMGTYPE}") # Crear Imagen. try: with open(IMGFILE + ".info", "w") as info_file: subprocess.run(PROGRAM, shell=True, check=True) info_file.write(f"{ogGetImageInfo(IMGFILE)}:{ogGetHostname()}") except subprocess.CalledProcessError: ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {args[1]} {IMGFILE}") os.remove(IMGFILE) return ERRCODE # Desbloquear disco e imagen. ogUnlockDisk(args[0]) ogUnlockImage(args[1], f"{args[2]}.{IMGTYPE}") return ERRCODE def ogCreateImage(*args): FUNCNAME = ogCreateImage.__name__ # Variables locales PART = "" PROGRAM = "" IMGDIR = "" IMGFILE = "" IMGTYPE = "" ERRCODE = "" # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} int_ndisk int_npart str_repo path_image", f"{FUNCNAME} 1 1 REPO /aula1/win7") return # Error si no se reciben entre 4 y 6 parámetros. if not (4 <= len(args) <= 6): ogRaiseError(OG_ERR_FORMAT, " ".join(args)) return # Comprobar que no está bloqueada ni la partición, ni la imagen. PART = ogDiskToDev(args[0], args[1]) if ogIsLocked(args[0], args[1]): ogRaiseError(OG_ERR_LOCKED, f"{MSG_LOCKED} {args[0]}, {args[1]}") return IMGTYPE = "img" # Extensión genérica de imágenes. IMGDIR = ogGetParentPath(args[2], args[3]) if not IMGDIR: ogRaiseError(OG_ERR_NOTFOUND, f"{args[2]} {os.path.dirname(args[3])}") return IMGFILE = f"{IMGDIR}/{os.path.basename(args[3])}.{IMGTYPE}" if ogIsImageLocked(IMGFILE): ogRaiseError(OG_ERR_LOCKED, f"{MSG_IMAGE} {args[2]}, {args[3]}") return # Generar la instruccion a ejecutar antes de aplicar los bloqueos. PROGRAM = ogCreateImageSyntax(PART, IMGFILE, *args[4:]) # Desmontar partición, bloquear partición e imagen. ogUnmount(args[0], args[1]) ogLock(args[0], args[1]) # Crear Imagen. try: with open(f"{IMGFILE}.info", "w") as info_file: subprocess.run(PROGRAM, shell=True, check=True) info_file.write(f"{ogGetImageInfo(IMGFILE)}:{ogGetHostname()}") except subprocess.CalledProcessError: ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {args[1]} {IMGFILE}") os.remove(IMGFILE) return ERRCODE # Desbloquear partición e imagen. ogUnlock(args[0], args[1]) ogUnlockImage(args[2], f"{args[3]}.{IMGTYPE}") return ERRCODE def ogCreateMbrImage(*args): FUNCNAME = ogCreateMbrImage.__name__ # Variables locales DISK = "" IMGDIR = "" IMGFILE = "" # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} int_ndisk str_repo path_image", f"{FUNCNAME} 1 REPO /aula1/mbr") return # Error si no se reciben 3 parámetros. if len(args) != 3: ogRaiseError(OG_ERR_FORMAT) return DISK = ogDiskToDev(args[0]) if not DISK: ogRaiseError(OG_ERR_NOTFOUND, args[0]) return IMGDIR = ogGetParentPath(args[1], args[2]) if not IMGDIR: ogRaiseError(OG_ERR_NOTFOUND, f"{args[1]} {os.path.dirname(args[2])}") return IMGFILE = f"{IMGDIR}/{os.path.basename(args[2])}.mbr" # Crear imagen del MBR. try: subprocess.run(["dd", f"if={DISK}", f"of={IMGFILE}", "bs=512", "count=1"], check=True) except subprocess.CalledProcessError: ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {IMGFILE}") return return def ogCreateBootLoaderImage(*args): FUNCNAME = ogCreateBootLoaderImage.__name__ # Variables locales DISK = "" IMGDIR = "" IMGFILE = "" # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} int_ndisk str_repo path_image", f"{FUNCNAME} 1 REPO /aula1/mbr") return # Error si no se reciben 3 parámetros. if len(args) != 3: ogRaiseError(OG_ERR_FORMAT) return DISK = ogDiskToDev(args[0]) if not DISK: ogRaiseError(OG_ERR_NOTFOUND, args[0]) return IMGDIR = ogGetParentPath(args[1], args[2]) if not IMGDIR: ogRaiseError(OG_ERR_NOTFOUND, f"{args[1]} {os.path.dirname(args[2])}") return IMGFILE = f"{IMGDIR}/{os.path.basename(args[2])}.mbr" # Crear imagen del Boot Loader dentro del MBR. try: subprocess.run(["dd", f"if={DISK}", f"of={IMGFILE}", "bs=446", "count=1"], check=True) except subprocess.CalledProcessError: ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {IMGFILE}") return return def ogGetSizeParameters(*args): FUNCNAME = ogGetSizeParameters.__name__ # Variables locales REPO = "" MNTDIR = "" SIZEDATA = "" KERNELVERSION = "" SIZEREQUIRED = "" FACTORGZIP = "" FACTORLZOP = "" FACTORSYNC = "" SIZEFREE = "" IMGTYPE = "" IMGDIR = "" IMGFILE = "" IMGEXT = "" IMGSIZE = "" ISENOUGHSPACE = "" # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} num_disk num_part str_repo path_imgname [monolit|sync|diff]", f"if {FUNCNAME} 1 2 REPO Windows10 sync ; then ...; fi", f"if {FUNCNAME} 1 6 Ubuntu16 CACHE ; then ...; fi") return # Error si no se reciben 1 o 2 parámetros. if len(args) < 4: return ogRaiseError(OG_ERR_FORMAT, f"{MSG_FORMAT}: {PROG} ndisco nparticion REPO|CACHE imgname [monolit|sync|diff]") # Recogemos parametros REPO = args[2].upper() IMGTYPE = f"_{args[4].upper()}_" MNTDIR = ogMount(args[0], args[1]) if not MNTDIR: return ogRaiseError(OG_ERR_PARTITION, f"{args[0]} {args[1]}") # Datos contenidos en la particion o en la lista de archivos de contiene la diferencial. if IMGTYPE == "_DIFF_": if not os.path.isfile("/tmp/ogimg.info"): return ogRaiseError(OG_ERR_NOTFOUND, "/tmp/ogimg.info") os.chdir(MNTDIR) with open("/tmp/ogimg.info", "r") as info_file: lines = info_file.readlines() lines = [line.strip() for line in lines if line.strip() != "/"] SIZEDATA = sum([os.path.getsize(line) for line in lines]) os.chdir("/") else: df_output = subprocess.run(["df", "-k"], capture_output=True, text=True).stdout df_lines = df_output.split("\n") for line in df_lines: if line.endswith(MNTDIR): SIZEDATA = line.split()[2] break # Aplicar factor de compresion if IMGTYPE == "_SYNC_" or IMGTYPE == "_DIFF_": # Sistema de fichero de la imagen según kernel, menor que 3.7 EXT4. comparamos revision KERNELVERSION = os.uname().release KERNELVERSION = float(KERNELVERSION.split("-")[0]) IMGFS = "EXT4" if KERNELVERSION < 3.07 else "BTRFS" FACTORSYNC = 130 # Si IMGFS="BTRFS" la compresion es mayor. if IMGFS == "BTRFS": FACTORSYNC -= 20 SIZEREQUIRED = SIZEDATA * FACTORSYNC // 100 # El tamaño mínimo del sistema de ficheros btrfs es 250M, ponemos 300 if SIZEREQUIRED < 300000: SIZEREQUIRED = 300000 else: FACTORGZIP = 55 / 100 FACTORLZOP = 65 / 100 SIZEREQUIRED = SIZEDATA * FACTORLZOP # Comprobar espacio libre en el contenedor. if REPO == "CACHE": SIZEFREE = ogGetFreeSize(ogFindCache()) elif REPO == "REPO": df_output = subprocess.run(["df", "-k"], capture_output=True, text=True).stdout df_lines = df_output.split("\n") for line in df_lines: if line.endswith(OGIMG): SIZEFREE = line.split()[3] break # Comprobamos si existe una imagen con el mismo nombre en $REPO # En sincronizadas restamos tamaño de la imagen y en monoloticas de la .ant if IMGTYPE == "_DIFF_": IMGEXT = "img.diff" elif IMGTYPE == "_SYNC_": IMGEXT = "img" else: IMGEXT = "img.ant" IMGDIR = ogGetParentPath(REPO, f"/{args[3]}") IMGFILE = ogGetPath(f"{IMGDIR}/{os.path.basename(f'/{args[3]}')}.{IMGEXT}") if IMGFILE == "": IMGSIZE = 0 else: IMGSIZE = os.path.getsize(IMGFILE) SIZEFREE += IMGSIZE ISENOUGHSPACE = "TRUE" if SIZEREQUIRED < SIZEFREE else "FALSE" return f"{SIZEDATA} {SIZEREQUIRED} {SIZEFREE} {ISENOUGHSPACE}" def ogIsImageLocked(*args): FUNCNAME = ogIsImageLocked.__name__ # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} [str_repo] path_image", f"if {FUNCNAME} /opt/opengnsys/images/aula1/win7.img; then ...; fi", f"if {FUNCNAME} REPO /aula1/win7.img; then ...; fi") return # Error si no se reciben 1 o 2 parámetros. if len(args) < 1 or len(args) > 2: return 1 # Comprobar si existe el fichero de bloqueo. if ogGetPath(*args) + ".lock": return True else: return False def ogLockImage(*args): FUNCNAME = ogLockImage.__name__ # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} [str_repo] path_image", f"if {FUNCNAME} /opt/opengnsys/images/aula1/win7.img; then ...; fi", f"if {FUNCNAME} REPO /aula1/win7.img; then ...; fi") return # Error si no se reciben 1 o 2 parámetros. if len(args) < 1 or len(args) > 2: return 1 # Comprobar que existe directorio de imagen IMGDIR = ogGetParentPath(*args) if not IMGDIR: return # Crear fichero de bloqueo. try: with open(f"{IMGDIR}/{os.path.basename(args[-1])}.lock", "w") as lock_file: pass except IOError: ogRaiseError(OG_ERR_NOTWRITE, " ".join(args)) return return def ogRestoreDiskImage(*args): FUNCNAME = ogRestoreDiskImage.__name__ # Variables locales DISK = "" DISKSIZE = "" IMGFILE = "" IMGTYPE = "" IMGSIZE = "" PROGRAM = "" ERRCODE = "" # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image int_ndisk", f"{FUNCNAME} REPO /aula1/win7 1") return # Error si no se reciben 3 parámetros. if len(args) != 3: ogRaiseError(OG_ERR_FORMAT) return # Procesar parámetros. DISK = ogDiskToDev(args[2]) if not DISK: return ogRaiseError(OG_ERR_NOTFOUND, f" {args[2]} {args[3]}") IMGTYPE = "dsk" IMGFILE = ogGetPath(args[0], f"{args[1]}.{IMGTYPE}") if not os.path.isfile(IMGFILE): return ogRaiseError(OG_ERR_NOTFOUND, f" {args[2]} {args[3]}") # comprobamos consistencia de la imagen if not ogGetImageInfo(IMGFILE): return ogRaiseError(OG_ERR_IMAGE, f" {args[0]} {args[1]}") #/* (Comienzo comentario Doxygen) # Error si la imagen no cabe en la particion. #IMGSIZE=$(ogGetImageSize "$1" "$2") || return $(ogRaiseError $OG_ERR_IMAGE " $1 $2"; echo $?) #DISKSIZE=$(ogGetDiskSize $3) #if [ $IMGSIZE -gt $DISKSIZE ]; then # ogRaiseError $OG_ERR_IMGSIZEPARTITION "$DISKSIZE < $IMGSIZE" # return $? #fi #*/ (Fin comentario Doxygen) # Comprobar el bloqueo de la imagen y de la partición. if ogIsImageLocked(IMGFILE): return ogRaiseError(OG_ERR_LOCKED, f"{MSG_IMAGE} {args[0]}, {args[1]}.{IMGTYPE}") if ogIsDiskLocked(args[2]): return ogRaiseError(OG_ERR_LOCKED, f"{MSG_DISK} {args[2]}") # Solicitamos la generación de la instruccion a ejecutar PROGRAM = ogRestoreImageSyntax(IMGFILE, DISK) # Bloquear el disco ogLockDisk(args[2]) try: # Ejecutar restauración según el tipo de imagen. subprocess.run(PROGRAM, shell=True, check=True) except subprocess.CalledProcessError: ogRaiseError(OG_ERR_IMAGE, f"{IMGFILE}, {args[2]}, {args[3]}") ERRCODE = 1 ogUnlockDisk(args[2], args[3]) return ERRCODE def ogRestoreImage(*args): FUNCNAME = ogRestoreImage.__name # Variables locales PART = "" PARTSIZE = "" IMGFILE = "" IMGTYPE = "" IMGSIZE = "" PROGRAM = "" ERRCODE = "" # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image int_ndisk int_npart", f"{FUNCNAME} REPO /aula1/win7 1 1") return # Error si no se reciben 4 parámetros. if len(args) != 4: ogRaiseError(OG_ERR_FORMAT) return # Procesar parámetros. PART = ogDiskToDev(args[2], args[3]) if not PART: return ogRaiseError(OG_ERR_NOTFOUND, f" {args[2]} {args[3]}") IMGTYPE = "img" IMGFILE = ogGetPath(args[0], f"{args[1]}.{IMGTYPE}") if not os.path.isfile(IMGFILE): return ogRaiseError(OG_ERR_NOTFOUND, f" {args[2]} {args[3]}") # comprobamos consistencia de la imagen if not ogGetImageInfo(IMGFILE): return ogRaiseError(OG_ERR_IMAGE, f" {args[0]} {args[1]}") # Error si la imagen no cabe en la particion. IMGSIZE = ogGetImageSize(args[0], args[1]) PARTSIZE = ogGetPartitionSize(args[2], args[3]) if IMGSIZE > PARTSIZE: ogRaiseError(OG_ERR_IMGSIZEPARTITION, f" {PARTSIZE} < {IMGSIZE}") return # Comprobar el bloqueo de la imagen y de la partición. if ogIsImageLocked(IMGFILE): return ogRaiseError(OG_ERR_LOCKED, f"{MSG_IMAGE} {args[0]}, {args[1]}.{IMGTYPE}") if ogIsLocked(args[2], args[3]): return ogRaiseError(OG_ERR_LOCKED, f"{MSG_PARTITION} {args[2]}, {args[3]}") # Solicitamos la generación de la instruccion a ejecutar PROGRAM = ogRestoreImageSyntax(IMGFILE, PART) # Desmontar y bloquear partición. ogUnmount(args[2], args[3]) ogLock(args[2], args[3]) try: # Ejecutar restauración según el tipo de imagen. subprocess.run(PROGRAM, shell=True, check=True) except subprocess.CalledProcessError: ogRaiseError(OG_ERR_IMAGE, f"{IMGFILE}, {args[2]}, {args[3]}") ERRCODE = 1 ogUnlock(args[2], args[3]) return ERRCODE def ogRestoreMbrImage(*args): FUNCNAME = ogRestoreMbrImage.__name__ # Variables locales DISK = "" IMGFILE = "" # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image int_ndisk", f"{FUNCNAME} REPO /aula1/mbr 1") return # Error si no se reciben 3 parámetros. if len(args) != 3: ogRaiseError(OG_ERR_FORMAT) return # Procesar parámetros. DISK = ogDiskToDev(args[2]) if not DISK: return ogRaiseError(OG_ERR_NOTFOUND, args[2]) IMGFILE = ogGetPath(args[0], f"{args[1]}.mbr") if not os.path.isfile(IMGFILE): return ogRaiseError(OG_ERR_NOTFOUND, IMGFILE) # Restaurar imagen del MBR. try: subprocess.run(["dd", f"if={IMGFILE}", f"of={DISK}", "bs=512", "count=1"], check=True) except subprocess.CalledProcessError: ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {IMGFILE}") return return def ogRestoreBootLoaderImage(*args): FUNCNAME = ogRestoreBootLoaderImage.__name__ # Variables locales DISK = "" IMGFILE = "" # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image int_ndisk", f"{FUNCNAME} REPO /aula1/mbr 1") return # Error si no se reciben 3 parámetros. if len(args) != 3: ogRaiseError(OG_ERR_FORMAT) return # Procesar parámetros. DISK = ogDiskToDev(args[2]) if not DISK: return ogRaiseError(OG_ERR_NOTFOUND, args[2]) IMGFILE = ogGetPath(args[0], f"{args[1]}.mbr") if not os.path.isfile(IMGFILE): return ogRaiseError(OG_ERR_NOTFOUND, IMGFILE) # Restaurar imagen del MBR. try: subprocess.run(["dd", f"if={IMGFILE}", f"of={DISK}", "bs=446", "count=1"], check=True) except subprocess.CalledProcessError: ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {IMGFILE}") return return def ogUnlockImage(*args): FUNCNAME = ogUnlockImage.__name__ # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} [str_repo] path_image", f"if {FUNCNAME} /opt/opengnsys/images/aula1/win7.img; then ...; fi", f"if {FUNCNAME} REPO /aula1/win7.img; then ...; fi") return # Error si no se reciben 1 o 2 parámetros. if len(args) < 1 or len(args) > 2: return 1 # Borrar fichero de bloqueo para la imagen. lock_file = f"{ogGetPath(*args)}.lock" os.remove(lock_file) return def ogGetImageInfo(*args): FUNCNAME = ogGetImageInfo.__name__ # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} path_filename", f"{FUNCNAME} /opt/opengnsys/images/prueba.img ==> PARTCLONE:LZOP:NTFS:5642158") return # Error si no se recibe 1 parámetro. if len(args) != 1: ogRaiseError(OG_ERR_FORMAT) return # Comprobando que el parámetro uno es un archivo. if not os.path.isfile(args[0]): ogRaiseError(OG_ERR_NOTFOUND, args[0]) return IMGDETECT = "FALSE" IMGFILE = args[0] FILEHEAD = f"/tmp/{os.path.basename(IMGFILE)}.infohead" COMPRESSOR = subprocess.run(["file", IMGFILE], capture_output=True, text=True).stdout.split()[1] if not ogCheckStringInGroup(COMPRESSOR, "gzip lzop"): ogRaiseError(OG_ERR_IMAGE, f"Image format is not valid {IMGFILE}") return try: with open(FILEHEAD, "w") as filehead: subprocess.run([COMPRESSOR, "-dc", IMGFILE], stdout=filehead, stderr=subprocess.DEVNULL) except subprocess.CalledProcessError: ogRaiseError(OG_ERR_IMAGE, f"Image format is not valid {IMGFILE}") return # Buscando Primera opción. if IMGDETECT == "FALSE": PARTCLONEINFO = subprocess.run(["partclone.info", FILEHEAD], capture_output=True, text=True).stdout if "size" in PARTCLONEINFO: TOOLS = "PARTCLONE" FS = PARTCLONEINFO.split(": ")[7].upper() if FS in ["HFS", "HFSPLUS", "FAT32"]: FSPLUS = PARTCLONEINFO.split(": ")[8].upper() SIZEFACTOR = 1000000 if "GB" in PARTCLONEINFO else 1024 if FSPLUS == "PLUS": FS = FS + FSPLUS SIZE = int(PARTCLONEINFO.split(": ")[16]) * SIZEFACTOR else: SIZE = int(PARTCLONEINFO.split(": ")[15]) * SIZEFACTOR else: SIZEFACTOR = 1000000 if "GB" in PARTCLONEINFO else 1024 SIZE = int(PARTCLONEINFO.split(": ")[10]) * SIZEFACTOR IMGDETECT = "TRUE" # Buscando segunda opción. if IMGDETECT == "FALSE" and not os.path.exists("/dev/loop2"): if "ntfsclone-image" in open(FILEHEAD).read(): NTFSCLONEINFO = subprocess.run(["ntfsclone", "--restore", "--overwrite", "/dev/loop2", "-"], input=open(FILEHEAD).read(), capture_output=True, text=True).stdout if "ntfsclone" in NTFSCLONEINFO: TOOLS = "NTFSCLONE" SIZE = int(NTFSCLONEINFO.split("(")[1].split(".")[0]) // 1000 FS = "NTFS" IMGDETECT = "TRUE" # Buscando Tercer opción. if IMGDETECT == "FALSE": PARTIMAGEINFO = subprocess.run(["partimage", "-B", "gui=no", "imginfo", FILEHEAD], capture_output=True, text=True).stdout if "Partition" in PARTIMAGEINFO: TOOLS = "PARTIMAGE" FS = PARTIMAGEINFO.split()[16].upper() SIZE = int(PARTIMAGEINFO.split()[35]) * 1024 * 1024 IMGDETECT = "TRUE" if "boot sector" in subprocess.run(["file", FILEHEAD], capture_output=True, text=True).stdout: TOOLS = "partclone.dd" FS = "" SIZE = "" IMGDETECT = "TRUE" # Comprobamos valores if not TOOLS or not COMPRESSOR or IMGDETECT == "FALSE": ogRaiseError(OG_ERR_IMAGE, f"Image format is not valid {IMGFILE}") return else: COMPRESSOR = COMPRESSOR.upper() return f"{TOOLS}:{COMPRESSOR}:{FS}:{SIZE}" def ogGetImageProgram(*args): FUNCNAME = ogGetImageProgram.__name__ # Si se solicita, mostrar ayuda. if "help" in args: return ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image", f"{FUNCNAME} REPO prueba ==> PARTCLONE") # Error si no se reciben 2 parámetros. if len(args) != 2: return ogRaiseError(OG_ERR_FORMAT) IMGFILE = ogGetPath(args[0], f"{args[1]}.img") if not os.path.isfile(IMGFILE): return ogRaiseError(OG_ERR_NOTFOUND, IMGFILE) return ogGetImageInfo(IMGFILE).split(":")[0] def ogGetImageCompressor(*args): FUNCNAME = ogGetImageCompressor.__name__ # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image", f"{FUNCNAME} REPO prueba ==> LZOP") return # Error si no se reciben 2 parámetros. if len(args) != 2: ogRaiseError(OG_ERR_FORMAT) return IMGFILE = ogGetPath(args[0], f"{args[1]}.img") if not os.path.isfile(IMGFILE): ogRaiseError(OG_ERR_NOTFOUND, IMGFILE) return return ogGetImageInfo(IMGFILE).split(":")[1] def ogGetImageType(*args): FUNCNAME = ogGetImageType.__name__ # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image", f"{FUNCNAME} REPO prueba ==> NTFS") return # Error si no se reciben 2 parámetros. if len(args) != 2: ogRaiseError(OG_ERR_FORMAT) return IMGFILE = ogGetPath(args[0], f"{args[1]}.img") if not os.path.isfile(IMGFILE): ogRaiseError(OG_ERR_NOTFOUND, IMGFILE) return return ogGetImageInfo(IMGFILE).split(":")[2] def ogGetImageSize(*args): FUNCNAME = ogGetImageSize.__name__ # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image", f"{FUNCNAME} REPO prueba ==> 5642158") return # Error si no se reciben 2 parámetros. if len(args) != 2: ogRaiseError(OG_ERR_FORMAT) return IMGFILE = ogGetPath(args[0], f"{args[1]}.img") if not os.path.isfile(IMGFILE): ogRaiseError(OG_ERR_NOTFOUND, IMGFILE) return return ogGetImageInfo(IMGFILE).split(":")[3] def ogCreateGptImage(*args): FUNCNAME = ogCreateGptImage.__name__ # Variables locales DISK = "" IMGDIR = "" IMGFILE = "" # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} int_ndisk path_dir str_image", f"{FUNCNAME} 1 REPO /aula1/gpt") return # Error si no se reciben 3 parámetros. if len(args) != 3: ogRaiseError(OG_ERR_FORMAT) return DISK = ogDiskToDev(args[0]) if not DISK: return ogRaiseError(OG_ERR_NOTFOUND, args[0]) IMGDIR = ogGetParentPath(args[1], args[2]) if not IMGDIR: return ogRaiseError(OG_ERR_NOTFOUND, f"{args[1]} {os.path.dirname(args[2])}") IMGFILE = f"{IMGDIR}/{os.path.basename(args[2])}.gpt" # Crear imagen de la tabla GPT. try: subprocess.run(["sgdisk", f"-b={IMGFILE}", DISK], check=True) except subprocess.CalledProcessError: return ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {IMGFILE}") return def ogRestoreGptImage(*args): FUNCNAME = ogRestoreGptImage.__name__ # Variables locales DISK = "" IMGFILE = "" # Si se solicita, mostrar ayuda. if "help" in args: ogHelp(FUNCNAME, f"{FUNCNAME} path_dir str_image int_ndisk", f"{FUNCNAME} REPO /aula1/gpt 1") return # Error si no se reciben 3 parámetros. if len(args) != 3: ogRaiseError(OG_ERR_FORMAT) return DISK = ogDiskToDev(args[2]) if not DISK: return ogRaiseError(OG_ERR_NOTFOUND, args[2]) IMGFILE = ogGetPath(args[0], f"{args[1]}.gpt") if not os.path.isfile(IMGFILE): return ogRaiseError(OG_ERR_NOTFOUND, IMGFILE) # Restaurar tabla GPT del disco. try: subprocess.run(["sgdisk", f"-l={IMGFILE}", DISK], check=True) except subprocess.CalledProcessError: return ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {IMGFILE}") return