source: client/engine/ImageLib.py @ af9a1d9

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

refs #585 Libraries convert to Python3

  • Property mode set to 100644
File size: 31.4 KB
Line 
1import subprocess
2
3from engine.DiskLib import *
4from engine.FileLib import *
5from engine.NetLib import *
6
7def ogCreateImageSyntax(*args):
8    FUNCNAME=ogCreateImageSyntax.__name__
9    # Si se solicita, mostrar ayuda.
10    if "help" in args:
11        ogHelp(FUNCNAME, f"{FUNCNAME} path_device path_imagefile [str_tool] [str_compressionlevel]",
12                f"{FUNCNAME} /dev/sda1 /opt/opengnsys/images/prueba.img partclone lzop",
13                f"{FUNCNAME} /dev/sda1 /opt/opengnsys/images/prueba.img")
14        return
15
16    # Error si no se reciben entre 2 y 4 parámetros.
17    if not (2 <= len(args) <= 4):
18        ogRaiseError(OG_ERR_FORMAT, " ".join(args))
19        return
20
21    # Asignación de parámetros.
22    DEV = args[0]
23    IMGFILE = args[1]
24    if len(args) == 2:
25        # Sintaxis por defecto OG DEV IMGFILE
26        TOOL = "partclone"
27        LEVEL = "gzip"
28    elif len(args) == 4:
29        # Sintaxis condicionada.
30        TOOL = args[2].lower()
31        LEVEL = args[3].lower()
32
33    if TOOL == "ntfsclone":
34        PARAM1 = f"ntfsclone --force --save-image -O - {DEV}"
35    elif TOOL in ["partimage", "default"]:
36        PARAM1 = f"partimage -M -f3 -o -d -B gui=no -c -z0 --volume=0 save {DEV} stdout"
37    elif TOOL == "partclone":
38        FS = ogGetFsType(ogDevToDisk(DEV))
39        if FS == "EXT[234]":
40            PARAM1 = "partclone.extfs"
41        elif FS == "BTRFS":
42            PARAM1 = "partclone.btrfs"
43        elif FS == "REISERFS":
44            PARAM1 = "partclone.reiserfs"
45        elif FS == "REISER4":
46            PARAM1 = "partclone.reiser4"
47        elif FS == "JFS":
48            PARAM1 = "partclone.jfs"
49        elif FS == "XFS":
50            PARAM1 = "partclone.xfs"
51        elif FS == "F2FS":
52            PARAM1 = "partclone.f2fs"
53        elif FS == "NILFS2":
54            PARAM1 = "partclone.nilfs2"
55        elif FS == "NTFS":
56            PARAM1 = "partclone.ntfs"
57        elif FS == "EXFAT":
58            PARAM1 = "partclone.exfat"
59        elif FS in ["FAT16", "FAT32"]:
60            PARAM1 = "partclone.fat"
61        elif FS in ["HFS", "HFSPLUS"]:
62            PARAM1 = "partclone.hfsp"
63        elif FS == "UFS":
64            PARAM1 = "partclone.ufs"
65        elif FS == "VMFS":
66            PARAM1 = "partclone.vmfs"
67        else:
68            PARAM1 = "partclone.imager"
69       
70        # Por compatibilidad, si no existe el ejecutable usar por defecto "parclone.dd".
71        if not subprocess.run(["which", PARAM1], capture_output=True).returncode:
72            PARAM1 = "partclone.dd"
73       
74        PARAM1 = f"{PARAM1} -d0 -F -c -s {DEV}"
75        # Algunas versiones de partclone.dd no tienen opción "-c".
76        if "-c" not in subprocess.run([PARAM1.split()[0], "--help"], capture_output=True).stdout.decode():
77            PARAM1 = PARAM1.replace(" -c ", " ")
78
79    # Comprobar que existe mbuffer.
80    if not subprocess.run(["which", "mbuffer"], capture_output=True).returncode:
81        PARAM2 = "| mbuffer -q -m 40M "
82    else:
83        PARAM2 = " "
84
85    # Nivel de compresion.
86    if LEVEL in ["0", "none"]:
87        PARAM3 = " > "
88    elif LEVEL in ["1", "lzop"]:
89        PARAM3 = " | lzop > "
90    elif LEVEL in ["2", "gzip"]:
91        PARAM3 = " | gzip -c > "
92    elif LEVEL in ["3", "bzip"]:
93        PARAM3 = " | bzip -c > "
94
95    # Sintaxis final.
96    if PARAM1:
97        return f"{PARAM1} {PARAM2} {PARAM3} {IMGFILE}"
98
99    return ogCreateImageSyntax
100
101def ogRestoreImageSyntax(*args):
102    FUNCNAME=ogRestoreImageSyntax.__name__
103    TOOL = ""
104    COMPRESSOR = ""
105    LEVEL = ""
106    PART = ""
107    IMGFILE = ""
108    FILEHEAD = ""
109    INFOIMG = ""
110
111    # Si se solicita, mostrar ayuda.
112    if "help" in args:
113        ogHelp(FUNCNAME, f"{FUNCNAME} filename partition [tool] [levelcompresor]",
114                f"{FUNCNAME} /opt/opengnsys/images/prueba.img /dev/sda1 [partclone] [lzop]")
115        return
116
117    # Error si no se reciben entre 2 y 4 parámetros.
118    if not (2 <= len(args) <= 4):
119        ogRaiseError(OG_ERR_FORMAT, " ".join(args))
120        return
121
122    # controlamos que el parametro 1 (imagen) es tipo file.
123    if not os.path.isfile(args[0]):
124        ogRaiseError(OG_ERR_NOTFOUND, args[0])
125        return
126
127    # Si 2 parametros (file-origen-, device-destino-) = ogGetImageFull($1)
128    if len(args) == 2:
129        IMGFILE = args[0]
130        PART = args[1]
131        INFOIMG = ogGetImageInfo(IMGFILE)
132        if INFOIMG:
133            TOOL = INFOIMG.split(":")[0]
134            COMPRESSOR = INFOIMG.split(":")[1]
135            return ogRestoreImageSyntax(IMGFILE, PART, TOOL, COMPRESSOR)
136
137    # Si cuatro parametros genera sintaxis
138    if len(args) == 4:
139        IMGFILE = args[0]
140        PART = args[1]
141        # comprobamos parametro herramienta compresion.
142        TOOL = args[2].lower()
143        # comprobar parámetro compresor.
144        LEVEL = args[3].lower()
145
146        if LEVEL in ["0", "none"]:
147            COMPRESSOR = " "
148        elif LEVEL in ["1", "lzop"]:
149            COMPRESSOR = " lzop -dc "
150        elif LEVEL in ["2", "gzip"]:
151            COMPRESSOR = " gzip -dc "
152        elif LEVEL in ["3", "bzip"]:
153            COMPRESSOR = " bzip -dc "
154        else:
155            ogRaiseError(OG_ERR_NOTFOUND, f"Compressor no valid {TOOL}")
156            return
157
158        # comprobar mbuffer
159        if shutil.which("mbuffer"):
160            MBUFFER = "| mbuffer -q -m 40M "
161        else:
162            MBUFFER = " "
163
164        if TOOL == "ntfsclone":
165            TOOL = f"| ntfsclone --restore-image --overwrite {PART} -"
166        elif TOOL == "partimage":
167            TOOL = f"| partimage -f3 -B gui=no restore {PART} stdin"
168        elif TOOL.startswith("partclone"):
169            TOOL = f"| partclone.restore -d0 -C -I -o {PART}"
170        elif TOOL == "dd":
171            TOOL = f"| pv | dd conv=sync,noerror bs=1M of={PART}"
172        else:
173            ogRaiseError(OG_ERR_NOTFOUND, f"Tools imaging no valid {TOOL}")
174            return
175
176        return f"{COMPRESSOR} {IMGFILE} {MBUFFER} {TOOL}"
177   
178def ogCreateDiskImage(*args):
179    FUNCNAME = ogCreateDiskImage.__name__
180    # Variables locales
181    DISK = ""
182    PROGRAM = ""
183    IMGDIR = ""
184    IMGFILE = ""
185    IMGTYPE = ""
186    ERRCODE = ""
187
188    # Si se solicita, mostrar ayuda.
189    if "help" in args:
190        ogHelp(FUNCNAME, f"{FUNCNAME} int_ndisk str_repo path_image",
191                f"{FUNCNAME} 1 REPO /disk1")
192        return
193
194    # Error si no se reciben entre 3 y 5 parámetros.
195    if not (3 <= len(args) <= 5):
196        ogRaiseError(OG_ERR_FORMAT, " ".join(args))
197        return
198
199    # Comprobar que no está bloqueada ni la partición, ni la imagen.
200    DISK = ogDiskToDev(args[0])
201    if ogIsDiskLocked(args[0]):
202        ogRaiseError(OG_ERR_LOCKED, f"{MSG_LOCKED} {args[0]}")
203        return
204
205    IMGTYPE = "dsk"  # Extensión genérica de imágenes de disco.
206    IMGDIR = ogGetParentPath(args[1], args[2])
207    if not IMGDIR:
208        ogRaiseError(OG_ERR_NOTFOUND, f"{args[1]} {os.path.dirname(args[2])}")
209        return
210
211    IMGFILE = f"{IMGDIR}/{os.path.basename(args[2])}.{IMGTYPE}"
212    if ogIsImageLocked(IMGFILE):
213        ogRaiseError(OG_ERR_LOCKED, f"{MSG_IMAGE} {args[2]}, {args[3]}")
214        return
215
216    # No guardar imagen en el propio disco (disco no incluido en el camino del repositorio).
217    if ogGetPath(args[1], "/").startswith(DISK):
218        ogRaiseError(OG_ERR_IMAGE, f"{args[1]} = {DISK}")
219        return
220
221    # Generar la instruccion a ejecutar antes de aplicar los bloqueos.
222    PROGRAM = ogCreateImageSyntax(DISK, IMGFILE)
223
224    # Desmontar todos los sistemas de archivos del disco, bloquear disco e imagen.
225    ogUnmountAll(args[0])
226    ogLockDisk(args[0])
227    ogLockImage(args[1], f"{args[2]}.{IMGTYPE}")
228
229    # Crear Imagen.
230    try:
231        with open(IMGFILE + ".info", "w") as info_file:
232            subprocess.run(PROGRAM, shell=True, check=True)
233            info_file.write(f"{ogGetImageInfo(IMGFILE)}:{ogGetHostname()}")
234    except subprocess.CalledProcessError:
235        ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {args[1]} {IMGFILE}")
236        os.remove(IMGFILE)
237        return ERRCODE
238
239    # Desbloquear disco e imagen.
240    ogUnlockDisk(args[0])
241    ogUnlockImage(args[1], f"{args[2]}.{IMGTYPE}")
242
243    return ERRCODE
244
245def ogCreateImage(*args):
246    FUNCNAME = ogCreateImage.__name__
247    # Variables locales
248    PART = ""
249    PROGRAM = ""
250    IMGDIR = ""
251    IMGFILE = ""
252    IMGTYPE = ""
253    ERRCODE = ""
254
255    # Si se solicita, mostrar ayuda.
256    if "help" in args:
257        ogHelp(FUNCNAME, f"{FUNCNAME} int_ndisk int_npart str_repo path_image",
258                f"{FUNCNAME} 1 1 REPO /aula1/win7")
259        return
260
261    # Error si no se reciben entre 4 y 6 parámetros.
262    if not (4 <= len(args) <= 6):
263        ogRaiseError(OG_ERR_FORMAT, " ".join(args))
264        return
265
266    # Comprobar que no está bloqueada ni la partición, ni la imagen.
267    PART = ogDiskToDev(args[0], args[1])
268    if ogIsLocked(args[0], args[1]):
269        ogRaiseError(OG_ERR_LOCKED, f"{MSG_LOCKED} {args[0]}, {args[1]}")
270        return
271
272    IMGTYPE = "img"  # Extensión genérica de imágenes.
273    IMGDIR = ogGetParentPath(args[2], args[3])
274    if not IMGDIR:
275        ogRaiseError(OG_ERR_NOTFOUND, f"{args[2]} {os.path.dirname(args[3])}")
276        return
277
278    IMGFILE = f"{IMGDIR}/{os.path.basename(args[3])}.{IMGTYPE}"
279    if ogIsImageLocked(IMGFILE):
280        ogRaiseError(OG_ERR_LOCKED, f"{MSG_IMAGE} {args[2]}, {args[3]}")
281        return
282
283    # Generar la instruccion a ejecutar antes de aplicar los bloqueos.
284    PROGRAM = ogCreateImageSyntax(PART, IMGFILE, *args[4:])
285
286    # Desmontar partición, bloquear partición e imagen.
287    ogUnmount(args[0], args[1])
288    ogLock(args[0], args[1])
289
290    # Crear Imagen.
291    try:
292        with open(f"{IMGFILE}.info", "w") as info_file:
293            subprocess.run(PROGRAM, shell=True, check=True)
294            info_file.write(f"{ogGetImageInfo(IMGFILE)}:{ogGetHostname()}")
295    except subprocess.CalledProcessError:
296        ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {args[1]} {IMGFILE}")
297        os.remove(IMGFILE)
298        return ERRCODE
299
300    # Desbloquear partición e imagen.
301    ogUnlock(args[0], args[1])
302    ogUnlockImage(args[2], f"{args[3]}.{IMGTYPE}")
303
304    return ERRCODE
305
306def ogCreateMbrImage(*args):
307    FUNCNAME = ogCreateMbrImage.__name__
308    # Variables locales
309    DISK = ""
310    IMGDIR = ""
311    IMGFILE = ""
312
313    # Si se solicita, mostrar ayuda.
314    if "help" in args:
315        ogHelp(FUNCNAME, f"{FUNCNAME} int_ndisk str_repo path_image",
316                f"{FUNCNAME} 1 REPO /aula1/mbr")
317        return
318
319    # Error si no se reciben 3 parámetros.
320    if len(args) != 3:
321        ogRaiseError(OG_ERR_FORMAT)
322        return
323
324    DISK = ogDiskToDev(args[0])
325    if not DISK:
326        ogRaiseError(OG_ERR_NOTFOUND, args[0])
327        return
328
329    IMGDIR = ogGetParentPath(args[1], args[2])
330    if not IMGDIR:
331        ogRaiseError(OG_ERR_NOTFOUND, f"{args[1]} {os.path.dirname(args[2])}")
332        return
333
334    IMGFILE = f"{IMGDIR}/{os.path.basename(args[2])}.mbr"
335
336    # Crear imagen del MBR.
337    try:
338        subprocess.run(["dd", f"if={DISK}", f"of={IMGFILE}", "bs=512", "count=1"], check=True)
339    except subprocess.CalledProcessError:
340        ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {IMGFILE}")
341        return
342
343    return
344
345def ogCreateBootLoaderImage(*args):
346    FUNCNAME = ogCreateBootLoaderImage.__name__
347    # Variables locales
348    DISK = ""
349    IMGDIR = ""
350    IMGFILE = ""
351
352    # Si se solicita, mostrar ayuda.
353    if "help" in args:
354        ogHelp(FUNCNAME, f"{FUNCNAME} int_ndisk str_repo path_image",
355                f"{FUNCNAME} 1 REPO /aula1/mbr")
356        return
357
358    # Error si no se reciben 3 parámetros.
359    if len(args) != 3:
360        ogRaiseError(OG_ERR_FORMAT)
361        return
362
363    DISK = ogDiskToDev(args[0])
364    if not DISK:
365        ogRaiseError(OG_ERR_NOTFOUND, args[0])
366        return
367
368    IMGDIR = ogGetParentPath(args[1], args[2])
369    if not IMGDIR:
370        ogRaiseError(OG_ERR_NOTFOUND, f"{args[1]} {os.path.dirname(args[2])}")
371        return
372
373    IMGFILE = f"{IMGDIR}/{os.path.basename(args[2])}.mbr"
374
375    # Crear imagen del Boot Loader dentro del MBR.
376    try:
377        subprocess.run(["dd", f"if={DISK}", f"of={IMGFILE}", "bs=446", "count=1"], check=True)
378    except subprocess.CalledProcessError:
379        ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {IMGFILE}")
380        return
381
382    return
383
384def ogGetSizeParameters(*args):
385    FUNCNAME = ogGetSizeParameters.__name__
386    # Variables locales
387    REPO = ""
388    MNTDIR = ""
389    SIZEDATA = ""
390    KERNELVERSION = ""
391    SIZEREQUIRED = ""
392    FACTORGZIP = ""
393    FACTORLZOP = ""
394    FACTORSYNC = ""
395    SIZEFREE = ""
396    IMGTYPE = ""
397    IMGDIR = ""
398    IMGFILE = ""
399    IMGEXT = ""
400    IMGSIZE = ""
401    ISENOUGHSPACE = ""
402
403    # Si se solicita, mostrar ayuda.
404    if "help" in args:
405        ogHelp(FUNCNAME, f"{FUNCNAME} num_disk num_part str_repo path_imgname [monolit|sync|diff]",
406                f"if {FUNCNAME} 1 2 REPO Windows10 sync ; then ...; fi",
407                f"if {FUNCNAME} 1 6 Ubuntu16 CACHE ; then ...; fi")
408        return
409
410    # Error si no se reciben 1 o 2 parámetros.
411    if len(args) < 4:
412        return ogRaiseError(OG_ERR_FORMAT, f"{MSG_FORMAT}: {PROG} ndisco nparticion REPO|CACHE imgname [monolit|sync|diff]")
413
414    # Recogemos parametros
415    REPO = args[2].upper()
416    IMGTYPE = f"_{args[4].upper()}_"
417
418    MNTDIR = ogMount(args[0], args[1])
419    if not MNTDIR:
420        return ogRaiseError(OG_ERR_PARTITION, f"{args[0]} {args[1]}")
421
422    # Datos contenidos en la particion o en la lista de archivos de contiene la diferencial.
423    if IMGTYPE == "_DIFF_":
424        if not os.path.isfile("/tmp/ogimg.info"):
425            return ogRaiseError(OG_ERR_NOTFOUND, "/tmp/ogimg.info")
426        os.chdir(MNTDIR)
427        with open("/tmp/ogimg.info", "r") as info_file:
428            lines = info_file.readlines()
429            lines = [line.strip() for line in lines if line.strip() != "/"]
430            SIZEDATA = sum([os.path.getsize(line) for line in lines])
431        os.chdir("/")
432    else:
433        df_output = subprocess.run(["df", "-k"], capture_output=True, text=True).stdout
434        df_lines = df_output.split("\n")
435        for line in df_lines:
436            if line.endswith(MNTDIR):
437                SIZEDATA = line.split()[2]
438                break
439
440    # Aplicar factor de compresion
441    if IMGTYPE == "_SYNC_" or IMGTYPE == "_DIFF_":
442        # Sistema de fichero de la imagen según kernel, menor que 3.7 EXT4. comparamos revision
443        KERNELVERSION = os.uname().release
444        KERNELVERSION = float(KERNELVERSION.split("-")[0])
445        IMGFS = "EXT4" if KERNELVERSION < 3.07 else "BTRFS"
446        FACTORSYNC = 130
447        # Si IMGFS="BTRFS" la compresion es mayor.
448        if IMGFS == "BTRFS":
449            FACTORSYNC -= 20
450
451        SIZEREQUIRED = SIZEDATA * FACTORSYNC // 100
452        # El tamaño mínimo del sistema de ficheros btrfs es 250M, ponemos 300
453        if SIZEREQUIRED < 300000:
454            SIZEREQUIRED = 300000
455    else:
456        FACTORGZIP = 55 / 100
457        FACTORLZOP = 65 / 100
458        SIZEREQUIRED = SIZEDATA * FACTORLZOP
459
460    # Comprobar espacio libre en el contenedor.
461    if REPO == "CACHE":
462        SIZEFREE = ogGetFreeSize(ogFindCache())
463    elif REPO == "REPO":
464        df_output = subprocess.run(["df", "-k"], capture_output=True, text=True).stdout
465        df_lines = df_output.split("\n")
466        for line in df_lines:
467            if line.endswith(OGIMG):
468                SIZEFREE = line.split()[3]
469                break
470
471    # Comprobamos si existe una imagen con el mismo nombre en $REPO
472    # En sincronizadas restamos tamaño de la imagen y en monoloticas de la .ant
473    if IMGTYPE == "_DIFF_":
474        IMGEXT = "img.diff"
475    elif IMGTYPE == "_SYNC_":
476        IMGEXT = "img"
477    else:
478        IMGEXT = "img.ant"
479
480    IMGDIR = ogGetParentPath(REPO, f"/{args[3]}")
481    IMGFILE = ogGetPath(f"{IMGDIR}/{os.path.basename(f'/{args[3]}')}.{IMGEXT}")
482    if IMGFILE == "":
483        IMGSIZE = 0
484    else:
485        IMGSIZE = os.path.getsize(IMGFILE)
486
487    SIZEFREE += IMGSIZE
488
489    ISENOUGHSPACE = "TRUE" if SIZEREQUIRED < SIZEFREE else "FALSE"
490
491    return f"{SIZEDATA} {SIZEREQUIRED} {SIZEFREE} {ISENOUGHSPACE}"
492
493def ogIsImageLocked(*args):
494    FUNCNAME = ogIsImageLocked.__name__
495    # Si se solicita, mostrar ayuda.
496    if "help" in args:
497        ogHelp(FUNCNAME, f"{FUNCNAME} [str_repo] path_image",
498                f"if {FUNCNAME} /opt/opengnsys/images/aula1/win7.img; then ...; fi",
499                f"if {FUNCNAME} REPO /aula1/win7.img; then ...; fi")
500        return
501
502    # Error si no se reciben 1 o 2 parámetros.
503    if len(args) < 1 or len(args) > 2:
504        return 1
505
506    # Comprobar si existe el fichero de bloqueo.
507    if ogGetPath(*args) + ".lock":
508        return True
509    else:
510        return False
511   
512def ogLockImage(*args):
513    FUNCNAME = ogLockImage.__name__
514    # Si se solicita, mostrar ayuda.
515    if "help" in args:
516        ogHelp(FUNCNAME, f"{FUNCNAME} [str_repo] path_image",
517                f"if {FUNCNAME} /opt/opengnsys/images/aula1/win7.img; then ...; fi",
518                f"if {FUNCNAME} REPO /aula1/win7.img; then ...; fi")
519        return
520
521    # Error si no se reciben 1 o 2 parámetros.
522    if len(args) < 1 or len(args) > 2:
523        return 1
524
525    # Comprobar que existe directorio de imagen
526    IMGDIR = ogGetParentPath(*args)
527    if not IMGDIR:
528        return
529
530    # Crear fichero de bloqueo.
531    try:
532        with open(f"{IMGDIR}/{os.path.basename(args[-1])}.lock", "w") as lock_file:
533            pass
534    except IOError:
535        ogRaiseError(OG_ERR_NOTWRITE, " ".join(args))
536        return
537
538    return
539
540def ogRestoreDiskImage(*args):
541    FUNCNAME = ogRestoreDiskImage.__name__
542    # Variables locales
543    DISK = ""
544    DISKSIZE = ""
545    IMGFILE = ""
546    IMGTYPE = ""
547    IMGSIZE = ""
548    PROGRAM = ""
549    ERRCODE = ""
550
551    # Si se solicita, mostrar ayuda.
552    if "help" in args:
553        ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image int_ndisk",
554                f"{FUNCNAME} REPO /aula1/win7 1")
555        return
556
557    # Error si no se reciben 3 parámetros.
558    if len(args) != 3:
559        ogRaiseError(OG_ERR_FORMAT)
560        return
561
562    # Procesar parámetros.
563    DISK = ogDiskToDev(args[2])
564    if not DISK:
565        return ogRaiseError(OG_ERR_NOTFOUND, f" {args[2]} {args[3]}")
566
567    IMGTYPE = "dsk"
568    IMGFILE = ogGetPath(args[0], f"{args[1]}.{IMGTYPE}")
569    if not os.path.isfile(IMGFILE):
570        return ogRaiseError(OG_ERR_NOTFOUND, f" {args[2]} {args[3]}")
571
572    # comprobamos consistencia de la imagen
573    if not ogGetImageInfo(IMGFILE):
574        return ogRaiseError(OG_ERR_IMAGE, f" {args[0]} {args[1]}")
575
576    #/* (Comienzo comentario Doxygen)
577    # Error si la imagen no cabe en la particion.
578    #IMGSIZE=$(ogGetImageSize "$1" "$2") || return $(ogRaiseError $OG_ERR_IMAGE " $1 $2"; echo $?)
579    #DISKSIZE=$(ogGetDiskSize $3)
580    #if [ $IMGSIZE -gt $DISKSIZE ]; then
581    #    ogRaiseError $OG_ERR_IMGSIZEPARTITION "$DISKSIZE < $IMGSIZE"
582    #    return $?
583    #fi
584    #*/ (Fin comentario Doxygen)
585
586    # Comprobar el bloqueo de la imagen y de la partición.
587    if ogIsImageLocked(IMGFILE):
588        return ogRaiseError(OG_ERR_LOCKED, f"{MSG_IMAGE} {args[0]}, {args[1]}.{IMGTYPE}")
589    if ogIsDiskLocked(args[2]):
590        return ogRaiseError(OG_ERR_LOCKED, f"{MSG_DISK} {args[2]}")
591
592    # Solicitamos la generación de la instruccion a ejecutar
593    PROGRAM = ogRestoreImageSyntax(IMGFILE, DISK)
594
595    # Bloquear el disco
596    ogLockDisk(args[2])
597    try:
598        # Ejecutar restauración según el tipo de imagen.
599        subprocess.run(PROGRAM, shell=True, check=True)
600    except subprocess.CalledProcessError:
601        ogRaiseError(OG_ERR_IMAGE, f"{IMGFILE}, {args[2]}, {args[3]}")
602        ERRCODE = 1
603
604    ogUnlockDisk(args[2], args[3])
605    return ERRCODE
606
607def ogRestoreImage(*args):
608    FUNCNAME = ogRestoreImage.__name
609    # Variables locales
610    PART = ""
611    PARTSIZE = ""
612    IMGFILE = ""
613    IMGTYPE = ""
614    IMGSIZE = ""
615    PROGRAM = ""
616    ERRCODE = ""
617
618    # Si se solicita, mostrar ayuda.
619    if "help" in args:
620        ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image int_ndisk int_npart",
621                f"{FUNCNAME} REPO /aula1/win7 1 1")
622        return
623
624    # Error si no se reciben 4 parámetros.
625    if len(args) != 4:
626        ogRaiseError(OG_ERR_FORMAT)
627        return
628
629    # Procesar parámetros.
630    PART = ogDiskToDev(args[2], args[3])
631    if not PART:
632        return ogRaiseError(OG_ERR_NOTFOUND, f" {args[2]} {args[3]}")
633
634    IMGTYPE = "img"
635    IMGFILE = ogGetPath(args[0], f"{args[1]}.{IMGTYPE}")
636    if not os.path.isfile(IMGFILE):
637        return ogRaiseError(OG_ERR_NOTFOUND, f" {args[2]} {args[3]}")
638
639    # comprobamos consistencia de la imagen
640    if not ogGetImageInfo(IMGFILE):
641        return ogRaiseError(OG_ERR_IMAGE, f" {args[0]} {args[1]}")
642
643    # Error si la imagen no cabe en la particion.
644    IMGSIZE = ogGetImageSize(args[0], args[1])
645    PARTSIZE = ogGetPartitionSize(args[2], args[3])
646    if IMGSIZE > PARTSIZE:
647        ogRaiseError(OG_ERR_IMGSIZEPARTITION, f" {PARTSIZE} < {IMGSIZE}")
648        return
649
650    # Comprobar el bloqueo de la imagen y de la partición.
651    if ogIsImageLocked(IMGFILE):
652        return ogRaiseError(OG_ERR_LOCKED, f"{MSG_IMAGE} {args[0]}, {args[1]}.{IMGTYPE}")
653    if ogIsLocked(args[2], args[3]):
654        return ogRaiseError(OG_ERR_LOCKED, f"{MSG_PARTITION} {args[2]}, {args[3]}")
655
656    # Solicitamos la generación de la instruccion a ejecutar
657    PROGRAM = ogRestoreImageSyntax(IMGFILE, PART)
658
659    # Desmontar y bloquear partición.
660    ogUnmount(args[2], args[3])
661    ogLock(args[2], args[3])
662    try:
663        # Ejecutar restauración según el tipo de imagen.
664        subprocess.run(PROGRAM, shell=True, check=True)
665    except subprocess.CalledProcessError:
666        ogRaiseError(OG_ERR_IMAGE, f"{IMGFILE}, {args[2]}, {args[3]}")
667        ERRCODE = 1
668
669    ogUnlock(args[2], args[3])
670    return ERRCODE
671
672def ogRestoreMbrImage(*args):
673    FUNCNAME = ogRestoreMbrImage.__name__
674    # Variables locales
675    DISK = ""
676    IMGFILE = ""
677
678    # Si se solicita, mostrar ayuda.
679    if "help" in args:
680        ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image int_ndisk",
681                f"{FUNCNAME} REPO /aula1/mbr 1")
682        return
683
684    # Error si no se reciben 3 parámetros.
685    if len(args) != 3:
686        ogRaiseError(OG_ERR_FORMAT)
687        return
688
689    # Procesar parámetros.
690    DISK = ogDiskToDev(args[2])
691    if not DISK:
692        return ogRaiseError(OG_ERR_NOTFOUND, args[2])
693   
694    IMGFILE = ogGetPath(args[0], f"{args[1]}.mbr")
695    if not os.path.isfile(IMGFILE):
696        return ogRaiseError(OG_ERR_NOTFOUND, IMGFILE)
697
698    # Restaurar imagen del MBR.
699    try:
700        subprocess.run(["dd", f"if={IMGFILE}", f"of={DISK}", "bs=512", "count=1"], check=True)
701    except subprocess.CalledProcessError:
702        ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {IMGFILE}")
703        return
704
705    return
706
707def ogRestoreBootLoaderImage(*args):
708    FUNCNAME = ogRestoreBootLoaderImage.__name__
709    # Variables locales
710    DISK = ""
711    IMGFILE = ""
712
713    # Si se solicita, mostrar ayuda.
714    if "help" in args:
715        ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image int_ndisk",
716                f"{FUNCNAME} REPO /aula1/mbr 1")
717        return
718
719    # Error si no se reciben 3 parámetros.
720    if len(args) != 3:
721        ogRaiseError(OG_ERR_FORMAT)
722        return
723
724    # Procesar parámetros.
725    DISK = ogDiskToDev(args[2])
726    if not DISK:
727        return ogRaiseError(OG_ERR_NOTFOUND, args[2])
728   
729    IMGFILE = ogGetPath(args[0], f"{args[1]}.mbr")
730    if not os.path.isfile(IMGFILE):
731        return ogRaiseError(OG_ERR_NOTFOUND, IMGFILE)
732
733    # Restaurar imagen del MBR.
734    try:
735        subprocess.run(["dd", f"if={IMGFILE}", f"of={DISK}", "bs=446", "count=1"], check=True)
736    except subprocess.CalledProcessError:
737        ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {IMGFILE}")
738        return
739
740    return
741
742def ogUnlockImage(*args):
743    FUNCNAME = ogUnlockImage.__name__
744    # Si se solicita, mostrar ayuda.
745    if "help" in args:
746        ogHelp(FUNCNAME, f"{FUNCNAME} [str_repo] path_image",
747                f"if {FUNCNAME} /opt/opengnsys/images/aula1/win7.img; then ...; fi",
748                f"if {FUNCNAME} REPO /aula1/win7.img; then ...; fi")
749        return
750
751    # Error si no se reciben 1 o 2 parámetros.
752    if len(args) < 1 or len(args) > 2:
753        return 1
754
755    # Borrar fichero de bloqueo para la imagen.
756    lock_file = f"{ogGetPath(*args)}.lock"
757    os.remove(lock_file)
758
759    return
760
761def ogGetImageInfo(*args):
762    FUNCNAME = ogGetImageInfo.__name__
763    # Si se solicita, mostrar ayuda.
764    if "help" in args:
765        ogHelp(FUNCNAME, f"{FUNCNAME} path_filename",
766                f"{FUNCNAME} /opt/opengnsys/images/prueba.img  ==>  PARTCLONE:LZOP:NTFS:5642158")
767        return
768
769    # Error si no se recibe 1 parámetro.
770    if len(args) != 1:
771        ogRaiseError(OG_ERR_FORMAT)
772        return
773
774    # Comprobando que el parámetro uno es un archivo.
775    if not os.path.isfile(args[0]):
776        ogRaiseError(OG_ERR_NOTFOUND, args[0])
777        return
778
779    IMGDETECT = "FALSE"
780    IMGFILE = args[0]
781    FILEHEAD = f"/tmp/{os.path.basename(IMGFILE)}.infohead"
782    COMPRESSOR = subprocess.run(["file", IMGFILE], capture_output=True, text=True).stdout.split()[1]
783    if not ogCheckStringInGroup(COMPRESSOR, "gzip lzop"):
784        ogRaiseError(OG_ERR_IMAGE, f"Image format is not valid {IMGFILE}")
785        return
786
787    try:
788        with open(FILEHEAD, "w") as filehead:
789            subprocess.run([COMPRESSOR, "-dc", IMGFILE], stdout=filehead, stderr=subprocess.DEVNULL)
790    except subprocess.CalledProcessError:
791        ogRaiseError(OG_ERR_IMAGE, f"Image format is not valid {IMGFILE}")
792        return
793
794    # Buscando Primera opción.
795    if IMGDETECT == "FALSE":
796        PARTCLONEINFO = subprocess.run(["partclone.info", FILEHEAD], capture_output=True, text=True).stdout
797        if "size" in PARTCLONEINFO:
798            TOOLS = "PARTCLONE"
799            FS = PARTCLONEINFO.split(": ")[7].upper()
800            if FS in ["HFS", "HFSPLUS", "FAT32"]:
801                FSPLUS = PARTCLONEINFO.split(": ")[8].upper()
802                SIZEFACTOR = 1000000 if "GB" in PARTCLONEINFO else 1024
803                if FSPLUS == "PLUS":
804                    FS = FS + FSPLUS
805                    SIZE = int(PARTCLONEINFO.split(": ")[16]) * SIZEFACTOR
806                else:
807                    SIZE = int(PARTCLONEINFO.split(": ")[15]) * SIZEFACTOR
808            else:
809                SIZEFACTOR = 1000000 if "GB" in PARTCLONEINFO else 1024
810                SIZE = int(PARTCLONEINFO.split(": ")[10]) * SIZEFACTOR
811            IMGDETECT = "TRUE"
812
813    # Buscando segunda opción.
814    if IMGDETECT == "FALSE" and not os.path.exists("/dev/loop2"):
815        if "ntfsclone-image" in open(FILEHEAD).read():
816            NTFSCLONEINFO = subprocess.run(["ntfsclone", "--restore", "--overwrite", "/dev/loop2", "-"], input=open(FILEHEAD).read(), capture_output=True, text=True).stdout
817            if "ntfsclone" in NTFSCLONEINFO:
818                TOOLS = "NTFSCLONE"
819                SIZE = int(NTFSCLONEINFO.split("(")[1].split(".")[0]) // 1000
820                FS = "NTFS"
821                IMGDETECT = "TRUE"
822
823    # Buscando Tercer opción.
824    if IMGDETECT == "FALSE":
825        PARTIMAGEINFO = subprocess.run(["partimage", "-B", "gui=no", "imginfo", FILEHEAD], capture_output=True, text=True).stdout
826        if "Partition" in PARTIMAGEINFO:
827            TOOLS = "PARTIMAGE"
828            FS = PARTIMAGEINFO.split()[16].upper()
829            SIZE = int(PARTIMAGEINFO.split()[35]) * 1024 * 1024
830            IMGDETECT = "TRUE"
831        if "boot sector" in subprocess.run(["file", FILEHEAD], capture_output=True, text=True).stdout:
832            TOOLS = "partclone.dd"
833            FS = ""
834            SIZE = ""
835            IMGDETECT = "TRUE"
836
837    # Comprobamos valores
838    if not TOOLS or not COMPRESSOR or IMGDETECT == "FALSE":
839        ogRaiseError(OG_ERR_IMAGE, f"Image format is not valid {IMGFILE}")
840        return
841    else:
842        COMPRESSOR = COMPRESSOR.upper()
843        return f"{TOOLS}:{COMPRESSOR}:{FS}:{SIZE}"
844   
845def ogGetImageProgram(*args):
846    FUNCNAME = ogGetImageProgram.__name__
847    # Si se solicita, mostrar ayuda.
848    if "help" in args:
849        return ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image",
850                        f"{FUNCNAME} REPO prueba  ==>  PARTCLONE")
851
852    # Error si no se reciben 2 parámetros.
853    if len(args) != 2:
854        return ogRaiseError(OG_ERR_FORMAT)
855
856    IMGFILE = ogGetPath(args[0], f"{args[1]}.img")
857    if not os.path.isfile(IMGFILE):
858        return ogRaiseError(OG_ERR_NOTFOUND, IMGFILE)
859
860    return ogGetImageInfo(IMGFILE).split(":")[0]
861
862def ogGetImageCompressor(*args):
863    FUNCNAME = ogGetImageCompressor.__name__
864    # Si se solicita, mostrar ayuda.
865    if "help" in args:
866        ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image",
867                f"{FUNCNAME} REPO prueba  ==>  LZOP")
868        return
869
870    # Error si no se reciben 2 parámetros.
871    if len(args) != 2:
872        ogRaiseError(OG_ERR_FORMAT)
873        return
874
875    IMGFILE = ogGetPath(args[0], f"{args[1]}.img")
876    if not os.path.isfile(IMGFILE):
877        ogRaiseError(OG_ERR_NOTFOUND, IMGFILE)
878        return
879
880    return ogGetImageInfo(IMGFILE).split(":")[1]
881
882def ogGetImageType(*args):
883    FUNCNAME = ogGetImageType.__name__
884    # Si se solicita, mostrar ayuda.
885    if "help" in args:
886        ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image",
887                f"{FUNCNAME} REPO prueba  ==>  NTFS")
888        return
889
890    # Error si no se reciben 2 parámetros.
891    if len(args) != 2:
892        ogRaiseError(OG_ERR_FORMAT)
893        return
894
895    IMGFILE = ogGetPath(args[0], f"{args[1]}.img")
896    if not os.path.isfile(IMGFILE):
897        ogRaiseError(OG_ERR_NOTFOUND, IMGFILE)
898        return
899
900    return ogGetImageInfo(IMGFILE).split(":")[2]
901
902def ogGetImageSize(*args):
903    FUNCNAME = ogGetImageSize.__name__
904    # Si se solicita, mostrar ayuda.
905    if "help" in args:
906        ogHelp(FUNCNAME, f"{FUNCNAME} str_repo path_image",
907                f"{FUNCNAME} REPO prueba  ==>  5642158")
908        return
909
910    # Error si no se reciben 2 parámetros.
911    if len(args) != 2:
912        ogRaiseError(OG_ERR_FORMAT)
913        return
914
915    IMGFILE = ogGetPath(args[0], f"{args[1]}.img")
916    if not os.path.isfile(IMGFILE):
917        ogRaiseError(OG_ERR_NOTFOUND, IMGFILE)
918        return
919
920    return ogGetImageInfo(IMGFILE).split(":")[3]
921
922def ogCreateGptImage(*args):
923    FUNCNAME = ogCreateGptImage.__name__
924    # Variables locales
925    DISK = ""
926    IMGDIR = ""
927    IMGFILE = ""
928
929    # Si se solicita, mostrar ayuda.
930    if "help" in args:
931        ogHelp(FUNCNAME, f"{FUNCNAME} int_ndisk path_dir str_image",
932                f"{FUNCNAME} 1 REPO /aula1/gpt")
933        return
934
935    # Error si no se reciben 3 parámetros.
936    if len(args) != 3:
937        ogRaiseError(OG_ERR_FORMAT)
938        return
939
940    DISK = ogDiskToDev(args[0])
941    if not DISK:
942        return ogRaiseError(OG_ERR_NOTFOUND, args[0])
943
944    IMGDIR = ogGetParentPath(args[1], args[2])
945    if not IMGDIR:
946        return ogRaiseError(OG_ERR_NOTFOUND, f"{args[1]} {os.path.dirname(args[2])}")
947
948    IMGFILE = f"{IMGDIR}/{os.path.basename(args[2])}.gpt"
949
950    # Crear imagen de la tabla GPT.
951    try:
952        subprocess.run(["sgdisk", f"-b={IMGFILE}", DISK], check=True)
953    except subprocess.CalledProcessError:
954        return ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {IMGFILE}")
955
956    return
957
958def ogRestoreGptImage(*args):
959    FUNCNAME = ogRestoreGptImage.__name__
960    # Variables locales
961    DISK = ""
962    IMGFILE = ""
963
964    # Si se solicita, mostrar ayuda.
965    if "help" in args:
966        ogHelp(FUNCNAME, f"{FUNCNAME} path_dir str_image int_ndisk",
967                f"{FUNCNAME} REPO /aula1/gpt 1")
968        return
969
970    # Error si no se reciben 3 parámetros.
971    if len(args) != 3:
972        ogRaiseError(OG_ERR_FORMAT)
973        return
974
975    DISK = ogDiskToDev(args[2])
976    if not DISK:
977        return ogRaiseError(OG_ERR_NOTFOUND, args[2])
978
979    IMGFILE = ogGetPath(args[0], f"{args[1]}.gpt")
980    if not os.path.isfile(IMGFILE):
981        return ogRaiseError(OG_ERR_NOTFOUND, IMGFILE)
982
983    # Restaurar tabla GPT del disco.
984    try:
985        subprocess.run(["sgdisk", f"-l={IMGFILE}", DISK], check=True)
986    except subprocess.CalledProcessError:
987        return ogRaiseError(OG_ERR_IMAGE, f"{args[0]} {IMGFILE}")
988
989    return
Note: See TracBrowser for help on using the repository browser.