import platform import os import re import time import logging import subprocess import shutil import glob import datetime logger = logging.getLogger ('boottools') def _run (args): cp = subprocess.run (args, text=True, capture_output=True) if cp.returncode: logger.error ('command "{}" failed with rc "{}"'.format (' '.join(args), cp.returncode)) logger.error ('stdout follows:') for i in cp.stdout.strip().split('\n'): logger.error (' ' + i) logger.error ('stderr follows:') for i in cp.stderr.strip().split('\n'): logger.error (' ' + i) raise Exception ('command "{}" failed with rc "{}"'.format (' '.join(args), cp.returncode)) stdout = cp.stdout.strip() stderr = cp.stderr.strip() return stdout, stderr def _grep (regex, file): with open (file, 'r') as f: for l in f: if (re.findall (regex, l)): return 1 return 0 def _is_mounted (mntpt): return _grep (mntpt, '/proc/mounts') def _umount (mntpt): if (_is_mounted (mntpt)): _run (['umount', mntpt]) def btogGetVar (osarch): btdir = '/tmp/opengnsys_installer/opengnsys/client/boot-tools' bttargetdir = '/var/lib/tftpboot/ogclient/' btrootfsimg = os.path.join (bttargetdir, 'ogclient.img') btrootfsmnt = os.path.join (bttargetdir, 'ogclientmount') btrootfsimglabel = 'ogClient' log_file = '/tmp/boot-tools_installation.log' versionboottools = 'ogLive' if 'i386' == osarch: btvirtualdisksize = '2000' # tamaño maximo limitado por schroot 2GB para 32 bits else: btvirtualdisksize = '3G' return btdir, bttargetdir, btrootfsimg, btrootfsmnt, btrootfsimglabel, log_file, versionboottools, btvirtualdisksize def btogGetOsInfo1 (type_client): ogclientcfg = '/tmp/ogclient.cfg' if 'precise' == type_client: # ogLive 1.0.4-rc2 basado en Ubuntu 12.04 LTS. osdistrib='ubuntu' oscodename='precise' osrelease='3.2.0-23-generic' osarch='i386' oshttp='http://es.archive.ubuntu.com/ubuntu/' elif 'wheezy' == type_client: # ogLive basado en Debian 7.3. osdistrib='debian' oscodename='wheezy' osrelease='3.2.0-4-i386' osarch='i386' oshttp='http://ftp.es.debian.org/debian/' elif 'quantal' == type_client: # ogLive 1.0.5-rc2 basado en Ubuntu 12.10 con Kernel descargado. osdistrib='ubuntu' oscodename='quantal' osrelease='3.7.6-030706-generic' osarch='i386' oshttp='http://es.archive.ubuntu.com/ubuntu/' elif 'raring' == type_client: # ogLive 1.0.5-rc3 basado en Ubuntu 13.04. osdistrib='ubuntu' oscodename='raring' osrelease='3.8.0-22-generic' osarch='i386' oshttp='http://es.archive.ubuntu.com/ubuntu/' elif 'trusty' == type_client: # ogLive 1.0.5-rc4 basado en Ubuntu 14.04. osdistrib='ubuntu' oscodename='trusty' osrelease='3.13.0-24-generic' osarch='i386' oshttp='http://es.archive.ubuntu.com/ubuntu/' elif 'vivid' == type_client: # ogLive 1.1.0-rc2 basado en Ubuntu 15.04. osdistrib='ubuntu' oscodename='vivid' osrelease='3.19.0-49-generic' osarch='i386' oshttp='http://es.archive.ubuntu.com/ubuntu/' elif 'wily' == type_client: # ogLive 1.1.0-rc1 basado en Ubuntu 15.10. osdistrib='ubuntu' oscodename='wily' osrelease='4.2.0-35-generic' osarch='i386' oshttp='http://es.archive.ubuntu.com/ubuntu/' elif 'xenial' == type_client or 'xenial-4.4' == type_client: # ogLive 1.1.0-rc4 basado en Ubuntu 16.04 y Kernel 4.4. osdistrib='ubuntu' oscodename='xenial' osrelease='4.4.0-34-generic' osarch='i386' oshttp='http://es.archive.ubuntu.com/ubuntu/' elif 'xenial-4.8' == type_client: # ogLive 1.1.0-rc5 basado en Ubuntu 16.04 y Kernel 4.8. osdistrib='ubuntu' oscodename='xenial' osrelease='4.8.0-39-generic' osarch='amd64' oshttp='http://es.archive.ubuntu.com/ubuntu/' elif 'xenial-4.13' == type_client: # ogLive 1.1.0-rc6 basado en Ubuntu 16.04 y Kernel 4.13. osdistrib='ubuntu' oscodename='xenial' osrelease='4.13.0-17-generic' osarch='amd64' oshttp='http://es.archive.ubuntu.com/ubuntu/' elif 'bionic' == type_client or 'bionic-4.15' == type_client: # ogLive 1.1.1-rc1 basado en Ubuntu 18.04 y Kernel 4.15. osdistrib='ubuntu' oscodename='bionic' osrelease='4.15.0-32-generic' osarch='amd64' oshttp='http://es.archive.ubuntu.com/ubuntu/' elif 'bionic-4.18' == type_client: # ogLive 1.1.1-rc3 basado en Ubuntu 18.04 y Kernel 4.18. osdistrib='ubuntu' oscodename='bionic' osrelease='4.18.0-20-generic' osarch='amd64' oshttp='http://es.archive.ubuntu.com/ubuntu/' elif 'bionic-5.0' == type_client: # ogLive 1.1.1-rc5 basado en Ubuntu 18.04 y Kernel 5.0. osdistrib='ubuntu' oscodename='bionic' osrelease='5.0.0-27-generic' osarch='amd64' oshttp='http://es.archive.ubuntu.com/ubuntu/' elif 'focal' == type_client: # ogLive 1.2.0-rc1 basado en Ubuntu 20.04 y Kernel 5.4. osdistrib='ubuntu' oscodename='focal' osrelease='5.4.0-42-generic' osarch='amd64' oshttp='http://es.archive.ubuntu.com/ubuntu/' elif 'noble' == type_client: # ogLive 1.2.0-rc1 basado en Ubuntu 24.04 y Kernel 6.8. osdistrib='ubuntu' oscodename='noble' osrelease='6.8.0-31-generic' osarch='amd64' oshttp='http://es.archive.ubuntu.com/ubuntu/' elif 'host' == type_client: # ogLive basado en la distribución del servidor. osdistrib=platform.freedesktop_os_release()['NAME'] oscodename=platform.freedesktop_os_release()['VERSION_CODENAME'] osrelease=platform.uname()[2] osarch, _=_run (['dpkg', '--print-architecture']) oshttp='http://es.archive.ubuntu.com/ubuntu/' else: # Parámetro desconocido print ('Parámetro no válido.') os.exit (1) return ogclientcfg, osdistrib, oscodename, osrelease, osarch, oshttp def btogGetOsInfo2 (type_client, versionboottools, ogclientcfg, osdistrib, oscodename, osrelease, osarch, oshttp): branch = 'master' giturl = f'https://api.github.com/repos/opengnsys/OpenGnsys/commits?sha={branch}&path=/client' gitrelease = 'r20240808' ## TODO: are we going to keep the following? $(curl -s "$GITURL" | jq -r '"r" + (.[0].commit.committer.date | split("-") | join("")[:8]) + "." + (.[0].sha[:7])') nameisoclient ='-'.join ([versionboottools, oscodename, osrelease, osarch, gitrelease]) namehostclient = '-'.join ([versionboottools, oscodename, gitrelease]) ### El fichero de configuración debe sustituir a estos 3 ficheros (borrar las 3 líneas siguientes). #echo "$NAMEISOCLIENT" > /tmp/opengnsys_info_rootfs #echo "$NAMEHOSTCLIENT" > /tmp/opengnsys_chroot # Generar fichero de configuración. with open (ogclientcfg, 'w') as f: print (f'TYPECLIENT="{type_client}"', file=f) print (f'OSDISTRIB="{osdistrib}"', file=f) print (f'OSCODENAME="{oscodename}"', file=f) print (f'OSRELEASE="{osrelease}"', file=f) print (f'OSARCH="{osarch}"', file=f) print (f'OSHTTP="{oshttp}"', file=f) print (f'GITRELEASE="{gitrelease}"', file=f) print (f'NAMEISOCLIENT="{nameisoclient}"', file=f) print (f'NAMEHOSTCLIENT="{namehostclient}"', file=f) return gitrelease, nameisoclient, namehostclient def btogSetFsVirtual (btrootfsimg, btrootfsimglabel, btrootfsmnt, btvirtualdisksize, bttargetdir, osarch): #if not btrootfsimg: btogGetVar() logger.info (f'Creación y formateo del disco virtual "{btrootfsimg}" "{btvirtualdisksize}" MB') try: _umount (btrootfsmnt) except: pass if (_is_mounted (btrootfsmnt)): raise Exception (f'failed to umount "{btrootfsmnt}"') try: os.makedirs (btrootfsmnt, exist_ok=True) except: raise Exception (f'Creando directorio "{btrootfsmnt}" : ERROR') try: _run (['chown', '-R', 'root:opengnsys', bttargetdir]) except: raise Exception (f'Failed to chown root:opengnsys "{btrootfsmnt}"') logger.info (f'Creating disk image "{btrootfsimg}"') if 'i386' == osarch: try: _run (['dd', 'if=/dev/zero', f'of={btrootfsimg}', 'bs=1048576', f'count={btvirtualdisksize}']) except: raise Exception (f'Creando el disco virtual "{btrootfsimg}" con tamaño maxima "{btvirtualdisksize}" MB : ERROR') else: try: _run (['qemu-img', 'create', btrootfsimg, btvirtualdisksize]) except: raise Exception (f'Creando el disco virtual "{btrootfsimg}" con tamaño maxima "{btvirtualdisksize}" MB : ERROR') logger.debug ('losetup --find') diskloop, _ = _run (['losetup', '--find']) if not diskloop: raise Exception ('no diskloop') logger.debug ('losetup attach') try: _run (['losetup', '--partscan', diskloop, btrootfsimg]) except: raise Exception ('losetup failed') logger.info ('Partitioning disk image') stdout, _ = _run (['bash', '-c', f"echo $'n\np\n1\n\n\nt\n83\nw' |fdisk {diskloop}"]) logger.debug (f'fdisk output follows: {stdout}') time.sleep (3) logger.debug ('losetup --detach') try: _run (['losetup', '--detach', diskloop]) except: raise Exception ('Liberando disco virtual despues del particionado: ERROR') logger.debug ('losetup --find') partloop, _ = _run (['losetup', '--find']) if not partloop: raise Exception ('no partloop') logger.debug ('losetup --offset attach') _run (['losetup', '--offset', '32256', partloop, btrootfsimg]) logger.info ('Creating ext4 filesystem') try: _run (['mkfs.ext4', '-b', '4096', '-L', btrootfsimglabel, partloop]) except: raise Exception ('Formateando la particion principal del disco virtual: ERROR') time.sleep (3) logger.debug ('losetup --detach') try: _run (['losetup', '--detach', partloop]) except: raise Exception ('Liberando la particion virtual despues del formateo: ERROR') logger.info (f'"{btrootfsimg}" "{btvirtualdisksize}" MB : OK') #btogSetFsAcces: habilita el acceso al sistema root del cliente con schroot def btogSetFsAccess (btrootfsimg): if (_grep (btrootfsimg, '/etc/schroot/schroot.conf')): return logger.info ('Iniciando la configuración del schroot') #cp /etc/schroot/schroot.conf /etc/schroot/schroot.conf.`getDateTime` if (os.path.exists ('/etc/schroot/schroot.conf')): shutil.copy ('/etc/schroot/schroot.conf', '/etc/schroot/schroot.conf.bak') with open ('/etc/schroot/schroot.conf', 'w') as f: print ('[IMGogclient]', file=f) print ('type=loopback', file=f) print ('file=/var/lib/tftpboot/ogclient/ogclient.img', file=f) print ('description=ogclient Ubuntu image', file=f) print ('#priority=1', file=f) print ('users=root', file=f) print ('groups=root', file=f) print ('root-groups=root', file=f) print ('mount-options=-o offset=32256', file=f) print ('root-users=root', file=f) #cp /etc/schroot/mount-defaults /etc/schroot/mount-defaults.`getDateTime` if (os.path.exists ('/etc/schroot/mount-defaults')): shutil.copy ('/etc/schroot/mount-defaults', '/etc/schroot/mount-defaults.bak') with open ('/etc/schroot/mount-defaults', 'w') as f: print ('# mount.defaults: static file system information for chroots.', file=f) print ('# Note that the mount point will be prefixed by the chroot path', file=f) print ('# (CHROOT_PATH)', file=f) print ('#', file=f) print ('# ', file=f) print ('proc /proc proc defaults 0 0', file=f) print ('#procbususb /proc/bus/usb usbfs defaults 0 0', file=f) print ('#/dev /dev none rw,bind 0 0', file=f) print ('/dev/pts /dev/pts none rw,bind 0 0', file=f) print ('/dev/shm /dev/shm none rw,bind 0 0', file=f) print ('#/home /home none rw,bind 0 0', file=f) print ('/tmp /tmp none rw,bind 0 0', file=f) map (os.unlink, glob.glob('/etc/schroot/setup.d/*chrootname')) #for i in glob.glob ('/etc/schroot/setup.d/*chrootname'): # os.unlink (i) logger.info ('Finalizado: OK') return 0 # btogSetfsBase: Genera el sistema root base con debootstrap # trabaja sobre un rootfs ya montado def btogSetFsBase (btrootfsimg, btrootfsmnt, osarch, oscodename, oshttp): logger.info ('Iniciando la generación del sistema de archivos') #mount | grep $BTROOTFSMNT || mount $BTROOTFSIMG $BTROOTFSMNT -o loop,offset=32256 if (not _is_mounted (btrootfsmnt)): raise Exception ('rootfs should be mounted') logger.info ('debootstrapping system') logger.debug (f'debootstrap --arch="{osarch}" --components=main,universe "{oscodename}" "{btrootfsmnt}" "{oshttp}"') try: _run (['debootstrap', f'--arch={osarch}', '--components=main,universe', oscodename, btrootfsmnt, oshttp]) except: if (_is_mounted (btrootfsmnt)): _run (['umount', btrootfsmnt]) raise Exception (f'debootstrap --arch="{osarch}" --components=main,universe "{oscodename}" "{btrootfsmnt}" "{oshttp}" : ha fallado!') logger.info (f'debootstrap --arch="{osarch}" --components=main,universe "{oscodename}" "{btrootfsmnt}" "{oshttp}" : ok') return 0 def boottoolsSshServer (btrootfsmnt): if not os.path.exists ('/root/.ssh/id_rsa'): ## crea un par de claves en la VM, no en el chroot _run (['ssh-keygen', '-q', '-f', '/root/.ssh/id_rsa', '-N', '']) #shutil.copy ('/root/.ssh/id_rsa.pub', '/tmp/') logger.debug ('comprobando directorio .ssh del root') if not os.path.exists (f'{btrootfsmnt}/root/.ssh'): ## crea directorio dentro del chroot logger.debug ('creando directorio .ssh 600') os.mkdir (f'{btrootfsmnt}/root/.ssh') os.chmod (f'{btrootfsmnt}/root/.ssh', 0o700) logger.debug ('creando el fichero authorized_keys') ## crea archivo en el chroot if not os.path.exists (f'{btrootfsmnt}/root/.ssh/authorized_keys'): open (f'{btrootfsmnt}/root/.ssh/authorized_keys', 'w').close() os.chmod (f'{btrootfsmnt}/root/.ssh/authorized_keys', 0o600) logger.debug ('importando la clave publica del servidor OG') #cat /tmp/id_rsa.pub if os.path.exists ('/root/.ssh/id_rsa.pub'): ## coge la publica de la VM y la pone en el authorized_keys del chroot #cat /tmp/id_rsa.pub >> /root/.ssh/authorized_keys fdin = open ('/root/.ssh/id_rsa.pub', 'r') fdout = open (f'{btrootfsmnt}/root/.ssh/authorized_keys', 'a') while True: l = fdin.readline() if not l: break fdout.write (l) fdin.close() fdout.close() else: logger.error ('no key publica og') def boottoolsSshClient (btrootfsmnt): if not os.path.exists (f'{btrootfsmnt}/root/.ssh/id_rsa'): _run (['ssh-keygen', '-q', '-f', f'{btrootfsmnt}/root/.ssh/id_rsa', '-N', '']) ## crea un par de claves en el chroot #cat /root/.ssh/id_rsa.pub >> /root/.ssh/authorized_keys ## coge la publica y se la autoriza a sí mismo fdin = open (f'{btrootfsmnt}//root/.ssh/id_rsa.pub', 'r') fdout = open (f'{btrootfsmnt}/root/.ssh/authorized_keys', 'a') while True: l = fdin.readline() if not l: break fdout.write (l) fdin.close() fdout.close() ## TODO: exportamos la publica a los repos #cp /root/.ssh/id_rsa.pub /tmp/rsa.ogclient.pub #btogFsInitrd genera un initrd. def btogFsInitrd (bttargetdir, osrelease): #echo "cp /tmp/*-${OSRELEASE} ${BTTARGETDIR}" #cp /tmp/*-${OSRELEASE} ${BTTARGETDIR} ## esto copia algo?? ## backup de oginitrd.img, oginitrd.img.sum, ogvmlinuz y ogvmlinuz.sum now = datetime.datetime.now(datetime.timezone.utc).strftime ('%Y%m%d-%H%M%S%z') if os.path.exists (f'{bttargetdir}/oginitrd.img'): os.rename (f'{bttargetdir}/oginitrd.img' , f'{bttargetdir}/oginitrd.img.{now}') os.rename (f'{bttargetdir}/oginitrd.img.sum', f'{bttargetdir}/oginitrd.img.sum.{now}') if os.path.exists (f'{bttargetdir}/ogvmlinuz'): os.rename (f'{bttargetdir}/ogvmlinuz' , f'{bttargetdir}/ogvmlinuz.{now}') os.rename (f'{bttargetdir}/ogvmlinuz.sum', f'{bttargetdir}/ogvmlinuz.sum.{now}') shutil.copy (f'/tmp/initrd.img-{osrelease}', f'{bttargetdir}/oginitrd.img') shutil.copy (f'/tmp/vmlinuz-{osrelease}', f'{bttargetdir}/ogvmlinuz') #DATASUM=`md5sum "${BTTARGETDIR}/oginitrd.img" | cut -f1 -d" "` md5, _ = _run (['md5sum', f'{bttargetdir}/oginitrd.img']) md5, rest = md5.split (' ', 1) #echo $DATASUM > ${BTTARGETDIR}/oginitrd.img.sum with open (f'{bttargetdir}/oginitrd.img.sum', 'w') as fd: fd.write (md5) #DATASUM=`md5sum "${BTTARGETDIR}/ogvmlinuz" | cut -f1 -d" "` md5, _ = _run (['md5sum', f'{bttargetdir}/ogvmlinuz']) md5, rest = md5.split (' ', 1) #echo $DATASUM > ${BTTARGETDIR}/ogvmlinuz.sum with open (f'{bttargetdir}/ogvmlinuz.sum', 'w') as fd: fd.write (md5) #cd - #chmod -R 755 $BTTARGETDIR for f in glob.glob (f'{bttargetdir}/oginitrd*') + glob.glob (f'{bttargetdir}/vmlinuz*'): os.chmod (f, 0o755) #btogFsSqfs convierte el sistema root en sqfs def btogFsSqfs (bttargetdir, btrootfsmnt): logger.info ('Iniciando la creación del sistema de archivos en sqfs') # si ya existe un sqfs lo renombramos if os.path.exists (f'{bttargetdir}/ogclient.sqfs'): now = datetime.datetime.now(datetime.timezone.utc).strftime ('%Y%m%d-%H%M%S%z') os.rename (f'{bttargetdir}/ogclient.sqfs', f'{bttargetdir}/ogclient.sqfs.{now}') _run (['mksquashfs', btrootfsmnt, f'{bttargetdir}/ogclient.sqfs']) os.chmod (f'{bttargetdir}/ogclient.sqfs', 0o744) #DATASUM=`md5sum "${BTTARGETDIR}/ogclient.sqfs" | cut -f1 -d" "` md5, _ = _run (['md5sum', f'{bttargetdir}/ogclient.sqfs']) md5, rest = md5.split (' ', 1) #echo $DATASUM > ${BTTARGETDIR}/ogclient.sqfs.sum with open (f'{bttargetdir}/ogclient.sqfs.sum', 'w') as fd: fd.write (md5) # btogIsoGenerator genera la iso del cliente def btogIsoGenerator (pxepkg, isolinux_tpl, bttargetdir, nameisoclient): #Preparamos los gestores de arranque try: os.makedirs ('/tmp/iso/isolinux', exist_ok=True) except: raise subprocess.run (['cp -a /usr/lib/syslinux/* /tmp/iso/isolinux/'], shell=True) if 'gpxe' == pxepkg: subprocess.run (['cp -a /usr/share/gpxe/* /tmp/iso/isolinux'], shell=True) elif 'ipxe' == pxepkg: subprocess.run (['cp -a /usr/lib/ipxe/* /tmp/iso/isolinux'], shell=True) else: raise Exception (f'unknown pxepkg value "{pxepkg}"') # Si existe el fichero ISO, montarlo para extraer isolinux.bin. if os.path.exists (f'/tmp/iso/isolinux/{pxepkg}.iso'): os.mkdir ('/tmp/iso/isolinux/mount') _run (['mount', '-o', 'loop', f'/tmp/iso/isolinux/{pxepkg}.iso', '/tmp/iso/isolinux/mount']) subprocess.run (['cp -a /tmp/iso/isolinux/mount/* /tmp/iso/isolinux'], shell=True) _run (['umount', '/tmp/iso/isolinux/mount']) os.rmdir ('/tmp/iso/isolinux/mount') os.unlink (f'/tmp/iso/isolinux/{pxepkg}.iso') ## ojo que aquí hay que interpolar $NAMEISOCLIENT y $PXEPKG with open ('/tmp/iso/isolinux/isolinux.cfg', 'w') as fd: fd.write (isolinux_tpl.strip().replace('__NAMEISOCLIENT__', nameisoclient).replace('__PXEPKG__', pxepkg)) # preparamos el directorio boot-tools. if not os.path.exists ('/tmp/iso/ogclient'): os.mkdir ('/tmp/iso/ogclient') shutil.copy (f'{bttargetdir}/ogclient.sqfs', '/tmp/iso/ogclient/') shutil.copy (f'{bttargetdir}/ogclient.sqfs.sum', '/tmp/iso/ogclient/') shutil.copy (f'{bttargetdir}/ogvmlinuz', '/tmp/iso/ogclient/') shutil.copy (f'{bttargetdir}/ogvmlinuz.sum', '/tmp/iso/ogclient/') shutil.copy (f'{bttargetdir}/ogvmlinuz', '/tmp/iso/ogclient/linuxISO') shutil.copy (f'{bttargetdir}/ogvmlinuz.sum', '/tmp/iso/ogclient/linuxISO.sum') shutil.copy (f'{bttargetdir}/oginitrd.img', '/tmp/iso/ogclient/') shutil.copy (f'{bttargetdir}/oginitrd.img.sum', '/tmp/iso/ogclient/') #el ogclienteToISO debe tener una copia del ogvmlinuz como linuxISO #cp -prv /var/lib/tftpboot/ogclientToIso/* /tmp/iso/ogclient oldpwd = os.getcwd() os.chdir ('/tmp') logger.debug (f'mkisofs -V ogClient -o {nameisoclient}.iso -b isolinux/isolinux.bin -c isolinux/boot.cat -J -no-emul-boot -boot-load-size 4 -boot-info-table /tmp/iso') _run (['mkisofs', '-V', 'ogClient', '-o', f'{nameisoclient}.iso', '-b', 'isolinux/isolinux.bin', '-c', 'isolinux/boot.cat', '-J', '-no-emul-boot', '-boot-load-size', '4', '-boot-info-table', '/tmp/iso']) ##Generamos el md5 #DATASUM=`md5sum ${NAMEISOCLIENT}.iso | cut -f1 -d" "` md5, _ = _run (['md5sum', f'{nameisoclient}.iso']) md5, rest = md5.split (' ', 1) #echo $DATASUM > ${NAMEISOCLIENT}.iso.sum with open (f'{nameisoclient}.iso.sum', 'w') as fd: fd.write (md5) os.chdir (oldpwd) os.rename (f'/tmp/{nameisoclient}.iso' , f'/var/lib/tftpboot/ogclient/{nameisoclient}.iso') os.rename (f'/tmp/{nameisoclient}.iso.sum', f'/var/lib/tftpboot/ogclient/{nameisoclient}.iso.sum') #def __unused_boottoolsBootGraphics(): # find /tmp/opengnsys_installer/ -name .svn -type d -exec rm -fr {} \; 2>/dev/null; # apt-get -y install plymouth plymouth-theme-script # update-alternatives --install /lib/plymouth/themes/default.plymouth default.plymouth /lib/plymouth/themes/opengnsys/opengnsys.plymouth 100 # update-alternatives --set default.plymouth /lib/plymouth/themes/opengnsys/opengnsys.plymouth # mkdir -p /etc/initramfs-tools/conf.d # echo "FRAMEBUFFER=y" > /etc/initramfs-tools/conf.d/splash