"Después del juego es antes del juego"
Sepp Herberger

jueves, 21 de enero de 2021

Preparando un dispositivo USB con arranque clonezilla e imágenes para restauración.

Siempre se me olvidan los pasos y tengo que andar mirando notas cuando me hace falta, así que voy a dejar aquí apuntados los métodos que tengo de crear un disco duro externo o pendrive autoarrancable con clonezilla y varias imágenes de disco.

Usaré clonezilla-live-2.5.5-38-amd64, que es el estándar que usamos en los centros educativos. Bajamos la versión amd64 en fichero zip mediante este enlace.

Asumirémos que el dispositivo USB está en la ruta /dev/sdd (con el comando "fdisk -l" podemos averiguar cual es el /dev/sdX que usa una vez pinchado en el puerto USB). A la hora de organizarlo tenemos dos opciones.
  1. Una única partición: se crea con gparted del tipo FAT32 y luego se formatea con:
    # mkfs.vfat -F 32 /dev/sdd1
  2. Usar dos particiones: con gparted creamos una (sdd1) con FAT32 de 256Mb o un poco mayor. El resto de disco con una partición (sdd2) de tipo NTFS o ext3/4 a la que pondremos la etiqueta "IMAGENES" para poder identificarla y montarla luego fácilmente. Una vez creadas las formateamos con:
    # mkfs.vfat -F 32 /dev/sdd1 
    # mkfs.ext3 /dev/sdd2
    # tune2fs –L IMAGENES /dev/sdd2
    
    o bien
    # mkfs.vfat -F 32 /dev/sdd1 
    # mkfs.ntfs /dev/sdd2
    # ntfslabel /dev/sdd2 IMAGENES
¿Qué diferencia hay entre poner una o dos particiones? Bueno, si ponemos una partición esta debe ser FAT32 por narices, con los límites de este formato (ficheros como mucho de 4GB y tamaño máximo de partición de 2TB). Además esa partición se monta de forma automática como "solo lectura", por tanto podemos restaurar imágenes pero no guardarlas en el dispositivo.

Con dos particiones, al ser la segunda extX o NTFS no tiene dichas limitaciones y además como la montamos en modo rw se puede tanto restaurar como guardar imágenes. Que cada cual elija su método favorito.

Una vez tenemos el disco con una o dos particiones preparado, lo conectamos y descomprimimos en la primera partición el fichero zip antes descargado, quedando la siguiente estructura de directorios dentro del mismo:
.
├── boot
│   └── grub
│       ├── efiboot.img
│       └── grub.cfg
├── Clonezilla-Live-Version
├── EFI
│   └── boot
│       ├── bootia32.efi
│       ├── bootx64.efi
│       ├── grub.cfg
│       ├── ocswp-grub2.png
│       └── unicode.pf2
├── GPL
├── home
│   └── partimag
├── live
│   ├── Clonezilla-Live-Version
│   ├── filesystem.packages
│   ├── filesystem.packages-remove
│   ├── filesystem.size
│   ├── filesystem.squashfs
│   ├── freedos.img
│   ├── initrd.img
│   ├── ipxe.efi
│   ├── ipxe.lkn
│   ├── memtest
│   └── vmlinuz
├── syslinux
│   ├── chain.c32
│   ├── drblwp.png
│   ├── isolinux.bin
│   ├── isolinux.cfg
│   ├── iso_sort.txt
│   ├── ldlinux.c32
│   ├── libcom32.c32
│   ├── libutil.c32
│   ├── memdisk
│   ├── menu.c32
│   ├── ocswp.png
│   ├── syslinux.cfg
│   └── vesamenu.c32
└── utils
    ├── linux
    │   ├── extlinux
    │   ├── makeboot.sh
    │   ├── syslinux
    │   └── VERSION.txt
    ├── mbr
    │   └── mbr.bin
    ├── README.txt
    ├── win32
    │   ├── makeboot.bat
    │   ├── syslinux.exe
    │   └── VERSION.txt
    └── win64
        ├── makeboot64.bat
        ├── syslinux64.exe
        └── VERSION.txt

13 directories, 45 files
Ahora hay que configurarlo como autoarrancable, eso lo hacemos con los comandos:
# cd /ruta/pendrive/utils/linux
# bash makeboot.sh /dev/sdd1
Con esto, ya tenemos el disco arrancable. Ahora hay que meter la imágenes clonezilla (recordemos que cada imagen de disco va un un subdirectorio separado) que queremos usar:
  1. Si usamos una partición, metemos las imágenes en el directorio /home/partimag de sdd1.
  2. Si usamos dos particiones, metemos las imágenes en el directorio raíz de sdd2
Por defecto, al arrancar clonezilla la primera partición del pendrive se monta en modo solo-lectura sobre /lib/live/mount/medium. Cuando se carga el programa principal (ocs-live-general) se enlaza /home/partimag sobre /lib/live/mount/medium/home/partimag. De esta manera, si al llegar al menú de selección de /home/partimag le decimos que use el ya existente (opción Skip) tendremos acceso directo a las imágenes allí contenidas.


El problema es cuando nuestras imágenes están en una partición distinta a sdd1. Podemos usar la opción "local_dev" de la captura anterior para montar dicha partición a mano o bien indicar en el arranque que se monte automáticamente. Para esto último debemos editar el fichero grub.cfg. Este fichero se guarda en la ruta EFI/boot/grub.cfg de la primera partición. Allí tendremos una serie de entradas como:
menuentry "Clonezilla live (Default settings, VGA 800x600)"{
  search --set -f /live/vmlinuz
  linux /live/vmlinuz boot=live union=overlay username=user config components quiet noswap edd=on nomodeset noeject locales= keyboard-layouts= ocs_live_run="ocs-live-general" ocs_live_extra_param="" ocs_live_batch="no" vga=788 ip= net.ifnames=0  splash i915.blacklist=yes radeonhd.blacklist=yes nouveau.blacklist=yes vmwgfx.enable_fbdev=1
  initrd /live/initrd.img
}
En esa entrada habría que añadir el comando:
ocs_prerun="mount -L IMAGENES /home/partimag"
El cual, efectivamente, monta la partición etiquetada como IMAGENES en la ruta /home/partimag antes de entrar en el programa general de clonezilla que, como podemos ver, se llama "ocs_live_general".

El resultado final es:
menuentry "Clonezilla live (Default settings, VGA 800x600)"{
  search --set -f /live/vmlinuz
  linux /live/vmlinuz boot=live union=overlay username=user config components quiet noswap edd=on nomodeset noeject locales= keyboard-layouts= ocs_prerun="mount -L IMAGENES /home/partimag" ocs_live_run="ocs-live-general" ocs_live_extra_param="" ocs_live_batch="no" vga=788 ip= net.ifnames=0  splash i915.blacklist=yes radeonhd.blacklist=yes nouveau.blacklist=yes vmwgfx.enable_fbdev=1
  initrd /live/initrd.img
}
De esta manera, al arrancar ya tendremos en /home/partimag las imágenes contenidas en la segunda partición del disco. Tan solo hay que escoger "Skip/Saltar: use existing /home/partimag" al llegar al llegar al menú de selección de /home/partimag.

Con esto tenemos resuelta la cuestión de tener un dispositivo que contenga tanto el clonezilla como las imágenes. Otra cosa que muchas veces se necesita es una opción que cargue una imagen de forma automática, sin intervención humana. En ese caso añadimos a EFI/boot/grub.cfg una opción como:
menuentry "Clonezilla restauracion automática imagen backup-dep"{
  search --set -f /live/vmlinuz
  linux /live/vmlinuz boot=live config components union=overlay noswap edd=on nomodeset noprompt ocs_prerun="mount -L IMAGENES /home/partimag" ocs_postrun="sudo shutdown -r now" ocs_live_run="ocs-live-restore" ocs_live_extra_param=" -e1 auto -e2 -r -j2 -scr -p true restoredisk backup-dep sda" keyboard-layouts="es" ocs_live_batch="yes" locales="es_ES.UTF-8" vga=791 ip=frommedia nosplash
  initrd /live/initrd.img
}
Que coge la imagen "backup-dep" desde la partición IMAGENES del dispositivo y la restaura en la unidad de disco duro /dev/sda, apagando el ordenador al finalizar. El truco está en:
ocs_live_run="ocs-live-restore" 
ocs_live_extra_param=" -e1 auto -e2 -r -j2 -scr -p true restoredisk backup-dep sda"}
Para cambiar el nombre de la imagen o el disco destino solo hay que modificar el fragmento "backup-dep sda". La explicación del resto de parámetros podemos encontrarla en este post del blog de mi compañero Esteban.


Seguimos para bingo con SpaceX, ya tenemos un Falcon 9 que ha sido utilizado 8 veces sin problemas. Esta vez ha aterrizado en la barcaza "Just Read The Instructions", con malas condiciones de viento y mar. Ha colocado en órbita otros 60 satélites Starlink, por lo que ya tenemos 1015 subidos para proporcionar Internet desde la órbita baja.
Según he leído en algún sitio, ya se han lanzado mas Falcon 9 que cualquier otro tipo de cohete en la historia. Y luego hay conspiranoicos que dicen que todo es CGI...

jueves, 7 de enero de 2021

Haciendo funcionar un dispositivo wifi USB Mediatek MT7601U en Linux.

Tengo un pincho USB wifi regalado que al probarlo no me funcionó en Linux. El sistema no creaba el dispositivo de red wifi al conectarlo. Su identificación USB es:
# lsusb | gre0 -i wireless
Bus 001 Device 003: ID 148f:7601 Ralink Technology, Corp. MT7601U Wireless Adapter
Lo curioso es que el driver mt7601u.ko si existe para Linux hace tiempo. En el caso de Manjaro tuve que instalarlo con:
$ pamac build  mt7601u-dkms-git
Una vez creado el módulo verifico que se carga en memoria:
# lsmod | grep mt
mt7601u               139264  0
mac80211             1110016  1 mt7601u
cfg80211              987136  2 mt7601u,mac80211
Pero nada, no funciona: no hay dispostivo wifi. Miro el log y veo estos errores recurrentemente:
   90.682395] mt7601u 1-1.1:1.0: ASIC revision: 76010001 MAC revision: 76010500
[   90.684079] mt7601u 1-1.1:1.0: Firmware Version: 0.1.00 Build: 7640 Build time: 201302052146____
[   91.066394] mt7601u 1-1.1:1.0: EEPROM ver:0c fae:00
[   91.232416] mt7601u 1-1.1:1.0: Error: MCU resp urb failed:-71
[   91.232420] mt7601u 1-1.1:1.0: Error: MCU resp evt:0 seq:5-4!
[   91.236894] mt7601u 1-1.1:1.0: Error: MCU resp urb failed:-71
[   91.236897] mt7601u 1-1.1:1.0: Error: MCU resp evt:0 seq:5-4!
[   91.241147] mt7601u 1-1.1:1.0: Error: MCU resp urb failed:-71
[   91.241150] mt7601u 1-1.1:1.0: Error: MCU resp evt:0 seq:5-4!
[   91.245395] mt7601u 1-1.1:1.0: Error: MCU resp urb failed:-71
[   91.245398] mt7601u 1-1.1:1.0: Error: MCU resp evt:0 seq:5-4!
[   91.249689] mt7601u 1-1.1:1.0: Error: MCU resp urb failed:-71
[   91.249692] mt7601u 1-1.1:1.0: Error: MCU resp evt:0 seq:5-4!
[   91.249694] mt7601u 1-1.1:1.0: Error: mt7601u_mcu_wait_resp timed out
[   91.439297] mt7601u 1-1.1:1.0: Vendor request req:07 off:0080 failed:-71
[   91.605971] mt7601u 1-1.1:1.0: Vendor request req:02 off:0080 failed:-71
[   91.772616] mt7601u 1-1.1:1.0: Vendor request req:02 off:0080 failed:-71
[   91.772671] mt7601u: probe of 1-1.1:1.0 failed with error -110
Buscando en Internet encuentro esta solución. Los pasos descritos son:

1) Descargamos el código fuente del driver:
# wget -O master.zip https://codeload.github.com/jeremyb31/mt7601u-5.3/zip/master
# unzip -x master.zip
2) Entramos en el directorio mt7601u-5.3-master y modificamos a mano el fichero phy.c en los lugares indicados:
En la función mt7601u_init_cal() comentar las líneas:
      // ret = mt7601u_mcu_calibrate(dev, MCU_CAL_RXIQ, 0);
      // if (ret)
      // return ret;
      // ret = mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->dpd_temp);
      // if (ret)
      // return ret;
En la función mt7601u_phy_recalibrate_after_assoc() comentar las línea:
      // mt7601u_mcu_calibrate(dev, MCU_CAL_DPD, dev->curr_temp);
3) Guardamos y compilamos para crear un fichero mt7601u.ko nuevo con los parches aplicados:
# make -C /lib/modules/$(uname -r)/build M=$(pwd) modules
4) Una vez hecho esto quitamos el pincho del puerto USB y descargamos el driver de la memoria:
# rmmod mt7601u
5) Cargamos el módulo nuevo y pinchamos el USB otra vez:
# insmod ./mt7601u.ko
Ahora si que se detecta la tarjeta wifi:
# iwconfig
lo        no wireless extensions.

eno1      no wireless extensions.

wlp0s26u1u1  IEEE 802.11  ESSID:"WLAN_985A3D"  
          Mode:Managed  Frequency:2.462 GHz  Access Point: 78:81:02:02:AB:F1   
          Bit Rate=57.8 Mb/s   Tx-Power=20 dBm   
          Retry short limit:7   RTS thr:off   Fragment thr:off
          Encryption key:off
          Power Management:off
          Link Quality=49/70  Signal level=-61 dBm  
          Rx invalid nwid:0  Rx invalid crypt:0  Rx invalid frag:0
          Tx excessive retries:128  Invalid misc:1890   Missed beacon:0
Por último solo hay que ponerlo en la ruta del driver original, para que se cargue en cada arranque de forma automática. Para saber la ubicación adecuada del fichero, reiniciamos la máquina y hacemos:
# modinfo mt7601u | grep -i filename
filename:       /lib/modules/5.10.2-2-MANJARO/kernel/drivers/net/wireless/mt7601u.ko.xz
En mi caso la ruta es /lib/modules/5.10.2-2-MANJARO/kernel/drivers/net/wireless/mt7601u.ko.xz. Comovvemos, está ademas comprimido con formato .xz. Haremos:
# mv /lib/modules/5.10.2-2-MANJARO/kernel/drivers/net/wireless/mt7601u.ko.xz /lib/modules/5.10.2-2-MANJARO/kernel/drivers/net/wireless/mt7601u.ko.xz.bak
# cp mt7601u.ko /lib/modules/5.10.2-2-MANJARO/kernel/drivers/net/wireless/mt7601u.ko
# cd /lib/modules/5.10.2-2-MANJARO/kernel/drivers/net/wireless
# xz mt7601u.ko
Y listo, ya todo queda funcionando. Tan solo recordar que si actualizamos el kernel tendremos que repetir estos pasos para regenerar el driver parcheado.

miércoles, 16 de diciembre de 2020

Enredando con una ROM Rockchip RK3326 (II): examinando las particiones de la imagen.

Ya hemos desempaquetado la ROM en Enredando con una ROM Rockchip RK3326 (I). Vamos ahora a ver la estructura. Tenemos un directorio donde se ha descomprimido la imagen:
# tree Image/
└── Image
   ├── boot.img
   ├── kernel.img
   ├── kernel.img.krnl
   ├── MiniLoaderAll.bin
   ├── misc.img
   ├── oem.img
   ├── parameter.txt
   ├── parameter.txt.parm
   ├── recovery.img
   ├── resource.img
   ├── system.img
   ├── trust.img
   ├── uboot.img
   └── vendor.img
Veamos de que tipo es cada fichero:
# file ./Image/*
boot.img:           Android bootimg, kernel (0x10008000), ramdisk (0x11000000), second stage (0x10f00000), page size: 2048, cmdline (buildvariant=user)
kernel.img:         data
kernel.img.krnl:    data
MiniLoaderAll.bin:  data
misc.img:           data
oem.img:            Android sparse image, version: 1.0, Total of 32768 4096-byte output blocks in 6 input chunks.
parameter.txt:      ASCII text, with very long lines
parameter.txt.parm: Par archive data
recovery.img:       Android bootimg, kernel (0x10008000), ramdisk (0x11000000), second stage (0x10f00000), page size: 2048, cmdline (buildvariant=user)
resource.img:       data
system.img:         Android sparse image, version: 1.0, Total of 665600 4096-byte output blocks in 20 input chunks.
trust.img:          data
uboot.img:          data
vendor.img:         Android sparse image, version: 1.0, Total of 98304 4096-byte output blocks in 8 input chunks.
Hay un poco de todo:
  • Ficheros en formato "data" (que significa "no sé que carajos hay ahí dentro")
  • Ficheros en formato "Android bootimg"
  • Ficheros en formato "Android sparse image"
Todo estos ficheros se corresponden con distintas particiones del sistema Android, que en el caso de nuestra tablet serian realmente:
Partition Info(gpt):
NO  LBA        Size       Name
01  0x00004000 0x00002000 uboot
02  0x00006000 0x00002000 trust
03  0x00008000 0x00002000 misc
04  0x0000a000 0x00008000 resource
05  0x00012000 0x00010000 kernel
06  0x00022000 0x00010000 boot
07  0x00032000 0x00020000 recovery
08  0x00052000 0x00038000 backup
09  0x0008a000 0x00002000 security
10  0x0008c000 0x000c0000 cache
11  0x0014c000 0x00514000 system
12  0x00660000 0x00008000 metadata
13  0x00668000 0x000c0000 vendor
14  0x00728000 0x00040000 oem
15  0x00768000 0x00000400 frp
16  0x00768400 0x032d5bdf userdata
Las particiones anteriores las averiguamos entrando en "adb shell" y haciendo algo de esto.

Como se ve, casi todas las particiones reales de la tablet se corresponden con un fichero .img de los extraidos de update.img. Al actualizar el firmware con update.img lo que se hace realmente es desempaquetar y escribir estos ficheros sobre cada partición, ni más ni menos.

Vamos a husmear dentro de las particiones que podamos descomprimir, a ver que encontramos. Las "data" no las tocamos porque no sabemos como abrirlas.

1. Examinando particiones Android bootimg.

Empezamos por boot.img, que está en formato "Android bootimg":
# wget https://storage.googleapis.com/google-code-archive-downloads/v2/code.google.com/android-serialport-api/android_bootimg_tools.tar.gz
# tar xfvz android_bootimg_tools.tar.gz
-rwxrwxr-x cedric/cedric 12095 2011-10-31 20:54 mkbootimg
-rwxrwxr-x cedric/cedric 11936 2011-10-31 20:54 unpackbootimg
# mkdir boot
# ./unpackbootimg -i /ruta/al/fichero/boot.img -o boot
Con esto se desempaqueta el contenido al directorio boot. Veamos que hay dentro:
# file boot/*
boot.img-base:     ASCII text
boot.img-cmdline:  ASCII text
boot.img-pagesize: ASCII text
boot.img-ramdisk:  ASCII cpio archive (SVR4 with no CRC)
boot.img-zImage:   data
En los 3 primeros ficheros son de configuración, los dos últimos son imágenes comprimidas de ramdisk e imagen boot. Vamos a descomprimir el ramdisk, que contiene dentro un sistema de ficheros:
# mkdir ramdisk
# cd ramdisk
# zcat ../boot.img-ramdisk.gz | cpio -idmv
# cd ..
# tree ramdisk
ramdisk/
├── acct
├── bugreports -> /data/user_de/0/com.android.shell/files/bugreports
├── cache -> /data/cache
├── charger -> /sbin/charger
├── config
├── d -> /sys/kernel/debug
├── data
├── default.prop -> system/etc/prop.default
├── dev
├── drmboot.ko
├── etc -> /system/etc
├── fstab.rk30board
├── init
├── init.connectivity.rc
├── init.environ.rc
├── init.optee.rc
├── init.rc
├── init.rk30board.bootmode.emmc.rc
├── init.rk30board.bootmode.nvme.rc
├── init.rk30board.bootmode.unknown.rc
├── init.rk30board.environment.rc
├── init.rk30board.rc
├── init.rk30board.usb.rc
├── init.rk3326.rc
├── init.rockchip.rc
├── init.usb.configfs.rc
├── init.usb.rc
├── init.zygote32.rc
├── init.zygote64_32.rc
├── mnt
├── oem
├── proc
├── res
│   └── images
│       └── charger
│           ├── battery_fail.png
│           ├── battery_scale.png
│           └── font.png
├── rk30xxnand_ko.ko
├── sbin
│   ├── charger
│   ├── mkdosfs
│   ├── ueventd -> ../init
│   └── watchdogd -> ../init
├── sdcard -> /storage/self/primary
├── storage
├── sys
├── system
├── ueventd.rc
├── ueventd.rk30board.rc
├── vendor
└── verity_key
Como se ve, tiene un sistema de ficheros con sus script y procesos para el arranque del tablet. Si hacemos lo mismo con recovery.img veremos que hay un minisistema Linux con muchas cositas. Recordemos que el recovery es un Linux que muestra un menú con ciertas funciones básicas de formateo y poco más.
# mkdir recovery
# ./unpackbootimg -i /ruta/al/fichero/recovery.img -o recovery
# cd ramdisk-recovery
# zcat ../recovery.img-ramdisk.gz | cpio -idmv
# cd ..
# tree ramdisk-recovery
ramdisk-recovery/
├── acct
├── bugreports -> /data/user_de/0/com.android.shell/files/bugreports
├── charger -> /sbin/charger
├── config
├── d -> /sys/kernel/debug
├── data
│   └── misc
│       └── wifi
├── default.prop -> prop.default
├── dev
├── drmboot.ko
├── etc
│   ├── bluetooth
│   ├── firmware
│   ├── mke2fs.conf
│   └── recovery.fstab
├── fstab.rk30board
├── init
├── init.rc
├── init.rk30board.usb.rc
├── init.usb.configfs.rc
├── init.usb.rc
├── lib
│   └── firmware
├── mnt
.........................
.........................
.........................
│   │       └── wifi_efuse_8723ds.map
│   ├── firmware
│   └── lib
│       └── modules
│           └── wifi
│               ├── 8188eu.ko
│               ├── 8188fu.ko
│               ├── 8189es.ko
│               ├── 8189fs.ko
│               ├── 8723bs.ko
│               ├── 8723bu.ko
│               ├── 8723cs.ko
│               ├── 8723ds.ko
│               ├── 8822be.ko
│               └── bcmdhd.ko
└── verity_key
Bueno, pues esto no tiene más. Vamos a avanzar mirando más cosas.

2. Examinando particiones Android sparse image.

Vamos a las otras particiones, las "Android sparse image": oem, vendor y system, descritas de forma general aquí. El formato "sparse image" es un tipo de imagen comprimido con menos huecos en blanco para ocupar menos tamaño. Para trabajar con su contenido hay que descomprimir el archivo antes de nada, usando la utilidad "simg2img" que está en el paquete Ubuntu "android-tools-fsutils".
# apt-get install android-tools-fsutils
# mkdir system
# cd system
# simg2img /ruta/al/fichero/system.img  system-no-sparse.img
# file system-no-sparse.img
system-no-sparse.img: Linux rev 1.0 ext4 filesystem data, UUID=bd2ccb6e-a94e-53be-9c80-3f438b342f58, volume name "system" (extents) (64bit) (large files) (huge files)
El sistema ext4 es ya un sistema manejable que podemos montar con "mount -o loop":
# mount -t auto -o loop system-no-sparse.img  mnt
# tree -d mnt/
├── app
│   ├── BasicDreams
│   │   └── oat
│   │       └── arm64
│   ├── Bluetooth
│   │   ├── lib
│   │   │   └── arm64
│   │   └── oat
│   │       └── arm64
......................
......................
│   └── YouTube
│       └── oat
│           ├── arm
│           └── arm64
├── bin
│   └── hw
├── etc
│   ├── bluetooth
│   ├── init
│   ├── permissions
│   ├── ppp
│   ├── preferred-apps
│   ├── seccomp_policy
│   ├── security
│   │   └── cacerts
│   ├── selinux
│   │   └── mapping
│   └── sysconfig
├── fake-libs
├── fake-libs64
├── fonts
├── framework
│   ├── arm
│   ├── arm64
│   └── oat
│       ├── arm
│       └── arm64
├── lib
│   ├── drm
│   ├── hw
│   ├── modules
│   └── vndk-sp
├── lib64
│   ├── drm
│   ├── hw
│   └── vndk-sp
├── lost+found
├── media
│   └── audio
│       ├── alarms
│       ├── notifications
│       ├── ringtones
│       └── ui
├── priv-app
│   ├── BackupRestoreConfirmation
│   │   └── oat
│   │       └── arm64
......................
......................
│   │       └── arm64
│   └── WallpaperCropper
│       └── oat
│           └── arm64
├── tts
│   └── lang_pico
└── usr
    ├── hyphen-data
    ├── icu
    ├── idc
    ├── keychars
    ├── keylayout
    ├── share
    │   ├── bmd
    │   └── zoneinfo
    └── srec
        └── en-US
Esta partición como vemos contiene el sistema android completo, que se monta sobre /system en el arranque, con todas las aplicaciones por defecto y todo el entorno y comandos. Si queremos retocar el firmware del tablet será esta partición la que hay que modificar.

Las otras dos particiones son oem.img y vendor.img. Oem "incorporates OEM (Original Equipment Manufacturer i.e. hardware manufacturer or Mobile Phone brand) small customization (modifications) to original Android (AOSP) during OTA updates such as customized system properties values etc.". Esta partición se monta sobre la ruta /oem cuando el tablet está en funcionamiento. La convertimos y montamos como hicimos con system:
# mkdir oem
# cd oem
# simg2img /ruta/al/fichero/oem.img  oem-no-sparse.img
# file oem-no-sparse.img
oem-no-sparse.img: Linux rev 1.0 ext4 filesystem data, UUID=bd2ccb6e-a94e-53be-9c80-3f438b342f58, volume name "oem" (extents) (64bit) (large files) (huge files)
# mkdir mnt-oem
# mount -t auto -o loop oem-no-sparse.img  mnt-ome
# tree mnt-oem/
mnt-oem/
├── etc
│   ├── fs_config_dirs
│   ├── fs_config_files
│   └── package_performance.xml
└── lost+found
Para la partición vendor "is sister partition of /system on Android devices which holds system applications and libraries that do not have source code available on AOSP but added by vendors (OEM's). It also contains SoC firmware images i.e. hardware specific libraries and binaries (OpenGL, ISP...). Proprietary blobs (HALs) usually live in /vendor as shared libraries (.so files) which are loaded by Android binders when processes call a hardware component. This partition was optional before Treble support and /vendor used to be just a symlink to /system/vendor"..
# mkdir vendor
# cd vendor
# simg2img /ruta/al/fichero/vendor.img  vendor-no-sparse.img
# mount -t auto -o loop vendor-no-sparse.img  mnt
# tree -d mnt/
├── bin
│   └── hw
├── etc
│   ├── bluetooth
│   ├── firmware
│   ├── init
│   ├── permissions
│   ├── seccomp_policy
│   ├── selinux
│   ├── usb_modeswitch.d
│   └── wifi
├── lib
│   ├── egl
│   ├── hw
│   ├── mediacas
│   ├── mediadrm
│   ├── modules
│   │   └── wifi
│   ├── optee_armtz
│   ├── soundfx
│   └── vndk-sp
├── lib64
│   ├── egl
│   ├── hw
│   ├── mediacas
│   ├── mediadrm
│   ├── soundfx
│   └── vndk-sp
├── lost+found
├── media
└── overlay
    └── SysuiDarkTheme
Y ya está. Supongo que la mayoría de las imágenes de los distintos sistemas Android se desempaquetará y manejará de una menera similar.


La sonda Chang'e-5 recogió sus 2kg de rocas lunares (ya era hora desde los años 70), despegó y está de vuelta.



Hoy 16 de diciembre caerá en algún sitio de Mongolia Interior (que buen lugar para mandar a algunos que yo me sé). Como vemos, si hace falta irán a caballo a recuperarla donde aterrice.


lunes, 14 de diciembre de 2020

Enredando con una ROM Rockchip RK3326 (I): desempaquetando la imagen.

Los tablets Techcomputer L108MR que nos enviaron tienen un chipset Rockchip rk3326 (esto lo averiguamos con un "adb shell getprop"). Como tenemos el fichero update.img con la imagen de la ROM suministrada por el distribuidor, he estado curioseando en sus entrañas, ya que no conocía mucho sobre estos chipsets del tipo Rockchip (muy usados en Android TV) y tenia interés por él. El fichero update.img viene en un formato desconocido:
# file update.img 
update.img: data
Hay varias maneras de desempaquetar este fichero para ver su contenido:

1. imgRePackerRK.

Empezamos con imgRePackerRK (RockChip's firmware images unpacker/packer). El nombre lo dice todo, lo descargamos y lo ejecutamos:
# ./imgrepackerrk update.img
	imgrepackerrk (version 1.06 linux)
	Rockchip firmware batch/update images unpacker/packer
    .....
	--- Firmware unpacking ---
	Can't open file "update.img" for reading
La primera en la frente. Dice que no puede abrir update.img. Tras mil pruebas no he sido capaz de hacer que funcione en Ubuntu: ni cambiando a otro sistema de archivos, ni cambiando permisos, ni nada. Pero probando en Windows si funciona, toma ya:
C:\Users\Administrador\Desktop\rockchip>imgrepackerrk update.img

        imgRepackerRK (version 1.06 windows)
        Rockchip firmware batch/update images unpacker/packer

        (c) RedScorpio, Moscow, 2013-2017
            RedScorpio@land.ru

        Detected OS:    Windows 7 Pro SP 1.0 [build 7601] x64
        ==========================[ START ]==========================

        --- Firmware unpacking ---

        "RKFW" image file detected

        Batch image header from "update.img" was read
        Image properties:
                Type            RockChip batch image ("RKFW")
                Version         8.1.0
                Date            2019.11.19
                Time            10:15:30
                ChipID          0x33333236
                Code(?)         0x01060000
                RKFWtype        0x00000001
                Unknown_1       0x00000000

        Unsupported ChipID
Se queja con "Unsupported ChipID". Menos mal que imgrepackerrk tiene el parámetro "/cid" para soslayar esto:
# imgrepackerrk 	Rockchip firmware batch/update images unpacker/packer

	(c) RedScorpio, Moscow, 2013-2017
	    RedScorpio@land.ru

	Usage:	./imgrepackerrk [options] 
	
		./imgrepackerrk [options] <[path/]name[.ext]>		- for unpacking
		./imgrepackerrk [options] <[path/]name[.ext]>.dump	- for packing
		./imgrepackerrk [options] <[path/]name[.ext]>.cfg	- for 2nd layer files packing
	
	Options:
		/log			- write log
		/debug			- debug mode on (works with /log option)
		/quiet			- don't output to console
		/mono			- monochrome mode on
		/md5			- ignore md5 errors (unpacking)
					- don't add md5 summ (packing)
		/rkcrc			- ignore RockChip CRC errors (unpacking)
		/rkaf			- make RKAF image (packing)
		/skip			- skip image size check (unpack option)
		/2nd			- unpack/pack 2-nd layer files
		/cid			- don't check ChipID (unpack option)
		/rmd4			- alignment of ramdisk in Android Boot image (pack option)
		/bcpath:		- base path for RKAndroidTool's cfg
		/lname:<[path]name>	- loader file name for RKAndroidTool's cfg
		/ini			- rewrite *.ini-file with new parameters
Por tanto, hacemos:
C:\Users\Administrador\Desktop\rockchip>imgrepackerrk /cid update.img

        imgRepackerRK (version 1.06 windows)
        Rockchip firmware batch/update images unpacker/packer

        (c) RedScorpio, Moscow, 2013-2017
            RedScorpio@land.ru

        Detected OS:    Windows 7 Pro SP 1.0 [build 7601] x64
        ==========================[ START ]==========================

        --- Firmware unpacking ---

        "RKFW" image file detected

        Batch image header from "update.img" was read
        Image properties:
                Type            RockChip batch image ("RKFW")
                Version         8.1.0
                Date            2019.11.19
                Time            10:15:30
                ChipID          0x33333236
                Code(?)         0x01060000
                RKFWtype        0x00000001
                Unknown_1       0x00000000

        -- boot.img processing --

        -- update.img processing --
        Update data header from "update.img" was read

        Corrected RKAF header properties
        Image properties:
                Type            RockChip update image ("RKAF")
                Id              "007"
                Model           "RK3326"
                Manufacturer    " RK3326"
                Version         8.1.0

        - Files extracting -
        Image files count = 14

        package-file (package-file)             extracted (format: unknown)
        bootloader (Image/MiniLoaderAll.bin)            extracted (format: RockChip bootloader image)
        parameter (Image/parameter.txt.parm)            extracted (format: RockChip PARM signed file)
        .....
        .....     
Y se desempaqueta todo en un directorio llamado update.img.dump con la estructura de todas las particiones contenidas en ella:
# tree update.img.dump/
update.img.dump/
├── config_16.cfg
├── config_8.cfg
├── Image
│   ├── boot.img
│   ├── kernel.img
│   ├── kernel.img.krnl
│   ├── MiniLoaderAll.bin
│   ├── misc.img
│   ├── oem.img
│   ├── parameter.txt
│   ├── parameter.txt.parm
│   ├── recovery.img
│   ├── resource.img
│   ├── system.img
│   ├── trust.img
│   ├── uboot.img
│   └── vendor.img
├── image.cfg
├── image.md5
└── package-file
El proceso inveso de generar un update.img a partir del directorio sería:
# imgrepackerrk udate.img.dump
.....
Genera un update.img que podríamos usar para actualizar completamente el dispositivo.

2. Herramientas oficiales de Rockchip para Linux.

En esta dirección de github tenemos Linux Pack Firmware, que trae scripts para empaquetado/desempaquetado de multitud de chipsets. Descargamos todo y haciendo:
# ./unpack.sh update.img
Este script (que internamente usa los ejecutables rkImageMaker y afptool) desempaqueta todo el contenido en el directorio "output".

La operación inversa se haría con el script "rk3326-mkupdate.sh":
# ls Image
boot.img  kernel.img  MiniLoaderAll.bin  misc.img  oem.img  parameter.txt  recovery.img  resource.img  system.img  trust.img  uboot.img  update.img  vendor.img
# ./rk3326-mkupdate.sh 
start to make update.img...
Android Firmware Package Tool v1.66
------ PACKAGE ------
Add file: ./package-file
Add file: ./package-file done,offset=0x800,size=0x2ac,userspace=0x1
Add file: ./Image/MiniLoaderAll.bin
Add file: ./Image/MiniLoaderAll.bin done,offset=0x1000,size=0x4714e,userspace=0x8f
Add file: ./Image/parameter.txt
Add file: ./Image/parameter.txt done,offset=0x48800,size=0x2aa,userspace=0x1
Add file: ./Image/trust.img
Add file: ./Image/trust.img done,offset=0x49000,size=0x400000,userspace=0x800
Add file: ./Image/uboot.img
Add file: ./Image/uboot.img done,offset=0x449000,size=0x400000,userspace=0x800
Add file: ./Image/misc.img
Add file: ./Image/misc.img done,offset=0x849000,size=0xc000,userspace=0x18
Add file: ./Image/resource.img
Add file: ./Image/resource.img done,offset=0x855000,size=0x119000,userspace=0x232
Add file: ./Image/kernel.img
Add file: ./Image/kernel.img done,offset=0x96e000,size=0x17c3014,userspace=0x2f87
Add file: ./Image/boot.img
Add file: ./Image/boot.img done,offset=0x2131800,size=0x1a46000,userspace=0x348c
Add file: ./Image/recovery.img
Add file: ./Image/recovery.img done,offset=0x3b77800,size=0x3c3f800,userspace=0x787f
Add file: ./Image/system.img
Add file: ./Image/system.img done,offset=0x77b7000,size=0x79491a14,userspace=0xf2924
Add file: ./Image/vendor.img
Add file: ./Image/vendor.img done,offset=0x80c49000,size=0xd08c07c,userspace=0x1a119
Add file: ./Image/oem.img
Add file: ./Image/oem.img done,offset=0x8dcd5800,size=0x3c064,userspace=0x79
Add CRC...
Make firmware OK!
------ OK ------
********RKImageMaker ver 1.66********
Generating new image, please wait...
Writing head info...
Writing boot file...
Writing firmware...
Generating MD5 data...
MD5 data generated successfully!
New image generated successfully!
Making update.img OK.
el cual, a partir del contenido del directorio Image como el mostrado en el código anterior crea un update.img nuevo.

Otra herramienta de desempaquetado de este repositorio github es Firmware Merger, pero no parece funcionar:
#  ./firmware_merger -U ./update.img update
Start to unpack firmware...
UnPacking Error:Tag of firmware is wrong, tag=0x57464b52!
Tampoco he indagado más.

3. Otras herramientas de terceros de Rockchip para Linux.

Hay muchos repositorios con proyectos personales que incluyen versiones particulares de herramientas de empaquetado/desempaquetado, como éste. Los pasos suelen ser:
# ./img_unpack update.img image.img
# mkdir img
#./afptool -unpack image.img img
....
UnPack OK!
Quedando todo desempaqetado en el directorio img.

4. Herramienta AndroidToolRelease de Windows.

Es una aplicación de Windows con interface gráfica para manejar firmwares de Rockchip. Antes de usarla hay que instalar los drivers mediante DriverAssistant. Para extraer el contenido de update.img vamos a la pestaña de Advanced Function y en Firmware seleccionamos el .img dando a "Unpack" luego. Eso desempaqueta todo.


Bueno, pues esta es la variedad de cosas que tenemos para desempaquetar update.img. En posts futuros husmearemos dentro de lo desempaquetado.


Ahí va, la Starship SN8 sube a 12.5km (las pruebas anteriores subieron 150m), apaga motores, baja en horizontal frenando con la atmósfera, se endereza... y se da el castañazo en el punto de partida. Explicado magistralmente por Daniel Marín.



La finalidad de la prueba, recopilar datos del planeo, ha sido exitosa. El aterrizaje perfecto hubiera estado bonito pero hubiera sido mucha suerte que funcionase. En fin, hemos estado 12.5km más cerca de Marte. Ahora a esperar en directo al SN9 cuando diga tito Elon.

jueves, 3 de diciembre de 2020

Alternar entre dos servidores DNS con un atajo de teclado.

He necesitado alternar entre el servidor DNS de mi red (192.168.1.100) y el de Google (8.8.8.8) para hacer unas pruebas con pihole. Como editar resolv.conf cada vez que quería cambiar el DNS es un coñazo, he hecho un script:
# cat /usr/local/bin/change_dns
#!/bin/bash

if grep "8.8.8.8" /etc/resolv.conf > /dev/null 2>&1
then
  sed -i "s/^nameserver.*$/nameserver 192.168.1.100/g" /etc/resolv.conf
else
  sed -i "s/^nameserver.*$/nameserver 8.8.8.8/g" /etc/resolv.conf
fi
exit 0
Para modificar el resolv.conf hay que ser root y yo quiero que esto lo haga cualquier usuario, asi que meto en /etc/sudoers:
# cat /etc/sudoers
.....
ALL   ALL = (ALL) NOPASSWD: /usr/local/bin/change_dns
.....
Ahora cualquier mindundi podrá ejecutarlo siendo root por un instante con "sudo /usr/local/bin/change_dns" o "gksu /usr/local/bin/change_dns".

Por último hay que definir el atajo de teclado para ejecutar el comando. Como usuario regular (no root) hacemos en un terminal:
$ xfconf-query -c xfce4-keyboard-shortcuts -p '/commands/custom/<Alt>d' --create -v -t string -s "gksu /usr/local/bin/change_dns"
Con esto vinculamos la combinacion de teclas Alt+d con la ejecución del script. Esto queda definido solo para el usuario actual, es decir, no es un atajo de teclado que se defina a nivel de sistema como hicimos aquí. La definición del atajo se guarda en:
$ cat .config/xfce4/xfconf/xfce-perchannel-xml/xfce4-keyboard-shortcuts.xml
<channel name="xfce4-keyboard-shortcuts" version="1.0">
  <property name="commands" type="empty">
    <property name="default" type="empty">
      .....
     <property name="custom" type="empty">
      <property name="override" type="bool" value="true"/>
      <property name="&lt;Alt&gt;d" type="string" value="gksu /usr/local/bin/change_dns"/>
      .......
    </property>
  </property>
  .....
</channel>
Y ya está, pulsando Alt-d pasa de un servidor DNS a otro de forma inmediata.
Bueno, ya está. La Chang'e 5 alunizó:



Ahora está recogiendo muestras, para subir, acoplarse al módulo de vuelta y traer el material a la Tierra. Es curioso, es el mismo esquema que el de una misión tripulada. Algo están tramando.

De momento nos deleitamos con esta preciosa foto de gran calidad:

lunes, 30 de noviembre de 2020

Cacharreo (IV): sustituir la fuente de alimentación de los altavoces de las pizarras Smart

Nuestras pizarras Smart 480 tienen estos altavoces tan majos:

Ya tienen varios años y van sufriendo bajas. La pieza que suele fallar es la fuente de alimentación, ubicada tras la pizarra y quemada en alguna subida de tensión:

Es una fuente de 18V y 3A, bastante rarita de encontrar, modelo GPE602-180300D que solo aparece en ebay USA a precio desorbitado. Además el conector de la clavija de alimentación tiene un diámetro un poco particular (algún día tendremos que hablar sobre este tema). Las fuentes mas parecidas que pude encontrar son las de los miniportátiles, de las cuales tenemos una burrada de ellas. Por ejemplo la de los miniportatiles APD:

Son 19V y 2.1A. En cuanto al voltaje la diferencia entre 18V y 19V normalmente no importa, lo que no podemos es meter 24V o 36V, ya que eso quemaría los altavoces. Por otro lados están los amperios: aqui podemos pasarnos tres pueblos sin problema ya que los altavoces cogen lo que necesitan y lo demás se ignora. El problema es que no es fácil encontrar fuentes de 3A, lo típico que tengamos 2.1A, como nos pasa ahora. Por enchufar esta fuente no se van a quemar los altavoces, el único problema sería que no diese la suficiente potencia para alimentar los mismos y no se encendiesen.

El otro problema es la clavija: la que tiene la fuente APD no entra en los altavoces, es más pequeña. Podemos cortar el cable de ambas fuentes, original y la del portátil, e intercambiar los extremos finales empalmando (ojo al empalmar, hay que respetar la polaridad + y -), pero hay una solución menos destructiva que solo nos haría cortar el cable de la fuente original (que, recordemos, está ya perdida). Para montajes eléctrónicos tengo estos conectores comprados en Amazon:

Tienen un tamaño estándar y la clavija del portátil APD entra perfectamente en el conector hembra. Así que corto el final del cable de la fuente de alimentación original de los altavoces y lo conecto a las clemas de la clavija (insisto: ojo con la polaridad. En mi caso el cable con la linea discontinua blanca es el positivo y el otro, sin linea alguna, es el negativo, pero no siempre es así. Lo mejor es ayudarse de un multímetro para no meter la pata):

A continuación, lo conecto a la fuente del miniportátil APD quedando todo:

De esta manera evitamos cortar el cable de la fuente APD, sería simplemente conectarla a este alargador y enchufarlo al altavoz.

Bueno, pues hecha conexión verifico que funciona y los altavoces van sin problema, pero tengo que comentar varias cosas muy importantes:

  • Probé con varias fuentes de otros portátiles similares (MSI, INVES) y no funcionaron. No daban suficiente potencia en amperios.
  • La causa del problema anterior es que muchas fuentes de alimentación tienen un circuito de seguridad que hace que se desconecten si les pedimos demasiada potencia. Evidentemente, la fuente APD no tiene este circuito y está trabajando por encima de su potencia sin apagarse.
  • ¿Es esto peligroso?: bueno, relativamente. Tengo montajes de este tipo alimentando aparatos eléctricos como una sierra caladora y no he tenido ningún problema. En el peor de los casos lo que podría suceder es que se quemase la propia fuente de alimentación por el sobreesfuerzo exigido.
  • ¿Funciona?: si. Llevo ya mas de 2 meses con el montaje y no hay problema. Me consta que hay compañeros con el mismo montaje hace años sin mayor problema. El único fallo previsible es que se acorte la vida de la fuente y haya que poner otra. No importa, total, tengo decenas.

Pues nada, taluec!

domingo, 29 de noviembre de 2020

Pasar a PDF el contenido de un blog de Blogger.

Tras 266 entradas he pensado que es un buen momento de hacer un backup de los datos del blog y tenerlos en una versión offline y legible.

Blogger tiene una función de backup, que genera un XML monstruoso, con una combinación de HTMLy XML para hacerlo visible en un navegador web, pero en un formato muy poco estructurado y que no incluye las imágenes. De todas maneras no es mala práctica bajar de vez en cuando este XML para tener una salvaguarda por si acaso.

Buscando en Internet, hay servicios online que te permiten convertir tu blog en un documento PDF o DOC, como BlogBooker, pero son de pago. Tienen un modo demo en que te permiten convertir varias entradas y la verdad es que quedan bastante bien.

Yo voy a intentar hacer algo mas modesto, pero que me salga gratis. Lo primero es descargar el XML del que hablamos antes, ya que ahí están todos los posts realizados al blog. La idea es extraer la URL de todas las entradas y convertirlas una a una en PDF.

1. Encontrar la URL de cada artículo del blog.

La URL de cada entrada del blog está dentro del galimatías del XML, probando y probando he logrado extraerlas todas con esta expresion regular de grep:
# grep -Eoi "'https://2tazasdelinux[^']+html'" blog-11-21-2020.xml
....
'https://2tazasdelinux.blogspot.com/2019/02/configuracion-e-impresion-con-impresora.html'
'https://2tazasdelinux.blogspot.com/2020/05/otra-herramienta-de-control-remoto.html'
'https://2tazasdelinux.blogspot.com/2020/05/otra-herramienta-de-control-remoto.html'
'https://2tazasdelinux.blogspot.com/2018/01/poner-las-aplicaciones-de-manjaro-en.html'
'https://2tazasdelinux.blogspot.com/2016/04/recopilar-mediante-puppet-de-forma.html'
....
Luego los ordenamos y eliminamos repetidos con:
#  grep -Eoi "'https://2tazasdelinux[^']+html'" blog-11-21-2020.xml | sort | uniq
2. Convertir una URL en un PDF claro y legible.

Con esto ya tenemos las URL de todas las entradas del blog. Ahora hay que iterar sobre ellas y convertirlas a PDF. Para ello usaremos wkhtmltopdf. El problema de convertirlas a PDF es que las páginas web son bastante barrocas entre cabeceras, pies, menús laterales, ventanas emergentes de aviso de cookies (maldigo desde aquí al que tuvo esa ocurrencia). Por ejemplo:
# wkhtmltopdf 'https://2tazasdelinux.blogspot.com/2020/11/usando-polkit-para-permitir-o.html' out.pdf
Genera un documento pdf como este:




La información está, pero es muy poco legible. Hay varios problemas que resolver:
  • El fondo del blog molesta visualmente: se puede quitar ejecutando wkhtmltopdf con la opción --no-background.
  • El texto no ocupa todo el ancho de la página: habría que modificar el diseño del blog para aumentar el ancho.
  • Los menús y paneles de la parte derecha de la página también molestan y deben ser ocultados.
  • El aviso de las cookies y la barra de navegacion superior también deberían desaparecer.
Para aumentar el ancho de la página y quitar los menús y paneles de la parte derecha hay que modificar el diseño del blog. Esto es muy personal, ya que cada uno tiene el tema de blog que le sale de las narices. En mi caso tengo el Simple Pale un poquitín personalizado. Antes de nada se aconseja hacer un backup del tema del blog, cosa que también se explica en el enlace que hemos pasado al principio del mensaje. Una vez hecho vamos a meternos a retocar el tema. Mostraré donde he tocado para despejar el mío:

Pinchando en Personalizar iríamos luego a Ajustar ancho y Diseño.
Ponemos el diseño en una sola columna:
Luego aumentando el ancho a 1200, nos quedaría:
Así queda bastante mas despejado. Todos los paneles laterales se han ido al final de la página y seguirían saliendo. Podríamos eliminar esos paneles sacándolos del diseño, pero veremos ahora otro sistema para ocultarlos.

Al hacer la captura nos aparece la ventanita de las cookies y la barra de navegacion superior. Eso no se puede quitar tocando el tema del blog, pero wkhtmltopdf permite ocultarlo por otra vía: el parámetro "--user-style-sheet estilo.css", que nos permite modificar los estilos de la página original antes de hacer la captura. Usando el siguiente fichero estilo.css nos libramos de ambas ventanitas y de todo lo que hay en el pie de la pagina (los antiguos paneles del lado derecho):
# cat estilo.css 
#cookieChoiceInfo { display: none; visibility: hidden; }
#b-navbar { display: none; visibility: hidden; }
#footer-1 { display: none; visibility: hidden; }
#footer-2-1 { display: none; visibility: hidden; }
#footer-2-2 { display: none; visibility: hidden; }
#footer-3 { display: none; visibility: hidden; }
Como vemos, seleccionamos diferentes elementos de estilo y los ocultamos. Evidentemente, hay que saber un poco de CSS para esto, pero no es complicado. Mirando en el diseño del Tema, podemos saber el nombre de muchos los elementos indeseables:

Para encontrar algún elemento rebelde (por ejemplo, la ventanita de las cookies), usando el Inspector de Página de Firefox es sencillo saber el nombre o clase CSS del objeto a ocultar (en nuestro caso son "#cookieChoiceInfo" y "#b-navbar".

Una vez afinado, lanzamos el wkhtmltopdf:
# wkhtmltopdf --no-background --user-style-sheet estilo.css 'http://2tazasdelinux.blogspot.com/2020/11/libro-digital-de-oxford-en-verde.html' out.pdf
Como se puede observar, esto tiene mucha mejor pinta:
Como ejemplo, aquí se puede descargar el fichero pdf resultante.

Bueno, pues el resto es pan comido: iterar sobre la lista de URL obtenidas en la primera parte y generar un pdf para cada una.
# cat blog-to-pdf 
#!/bin/bash

url="https://2tazasdelinux.blogspot.com/"
long=${#url}
backup="blog-11-21-2020.xml" # Backup XML del blog descargado desde Blogger

for url_entrada in $(grep -Eoi "'${url}[^']+html'" $backup | sort | uniq | tail -4)
do
  #A partir de la URL formamos un nombre legible para el fichero .pdf
  url_entrada=${url_entrada:1:-1} #Quitamos las comillas simples, dan problemas con wkhtmltopdf
  name=${url_entrada%.html}
  name=${name:$long}
  name=$(echo ${name}.pdf | tr '/' '-')
  echo "Descargando $url_entrada a $name"
  wkhtmltopdf --no-background --user-style-sheet estilo.css $url_entrada $name
done
exit 0
Pues con esto en un rato tenemos nuestro blog listo en PDF fáciles de leer. No olvidemos dejar el Tema del blog otra vez en orden al acabar la descarga de todos los artículos.

Out!

jueves, 26 de noviembre de 2020

Cambio automático de clave de wifi en punto de acceso OpenWrt.

El objetivo de esta entrada es configurar un punto de acceso que encenderá y apagará la red wifi a determinadas horas y que cada cierto tiempo cambiará automáticamente la clave. Todo se hará desde un ordenador externo que conectará por ssh con el OpenWRT del punto de acceso y ejecutará los comandos.

Lo primero es un script que calcule una nueva clave y la guarde en el fichero /root/scripts/wifi/clavewifi.txt.
# cat /root/scripts/generaClaveWifi.sh 
#!/bin/bash

claveletra=$(cat /dev/urandom | tr -dc abcdefghjklmnpqrstuvwxy | fold -w 2 | head -n 1)
clavenumero=$(cat /dev/urandom | tr -dc 0123456789 | fold -w 2 | head -n 1)
clave=$claveletra$clavenumero$claveletra$clavenumero
echo $clave > /root/scripts/wifi/clavewifi.txt
exit 0
La clave tiene el formato siguiente: 2 letras minúsculas y 2 dígitos, repetidos 2 veces. Por ejempo: "hx45hx45". El script es fácil de adaptar para cualquier otra combinación que deseemos.

Ahora el script que cambia la clave:
# cat /root/scripts/ponClaveWifi.sh 
#!/bin/bash

clave=$(cat /root/scripts/wifi/clavewifi.txt)
clave_router="claveopenwrt"
ssid="MI_WIFI"
security="WPA"
ip_openwrt="192.168.X.Y"
interface="1" #En mi caso la wifi está en el Interface 1.
comando="uci set wireless.@wifi-iface[$interface].key=$clave ; uci commit wireless ; wifi"
sshpass  -p $clave_router ssh -o StrictHostKeyChecking=no root@$ip_openwrt "$comando" > /dev/null 2>&1

qrencode -o /root/scripts/wifi.png "WIFI:S:${ssid};T:${security};P:${clave};;"

convert /root/scripts/wifi.png -background "black" -gravity south -extent 450x350  /root/scripts/wifi-canvas.png > /dev/null 2>&1
convert -pointsize 35 -fill white -draw "text 60,100 \"SSID: $ssid\" text 60,160 \"CLAVE: $clave\"" /root/scripts/wifi-canvas.png /root/scripts/wifi-key.png > /dev/null 2>&1
id_googledrive=1jMw8ixuAaR2RONW6IDmxii7nBdg4eJfZ
gdrive update $id_googledrive wifi-key.png > /dev/null 2>&1

exit 0
El script conecta con el punto de acceso mediante sshpass y ejecuta la secuencia de comands que cambian la clave, que son:
uci set wireless.@wifi-iface[$interface].key=$clave ; uci commit wireless ; wifi
El número con el $interface wifi a manejar lo determinamos previamente ejecutando a mano "uci show wireless", que muestra todas las interfaces que hay en nuestro router (lo normal es que haya dos, una emitiendo a 5Ghz y otra a 2.4Ghz).

Posteriormente creamos una imagen mediante qrencode que incluye un código QR conteniendo los datos de la wifi (ssid/contraseña) y añadimos mediante convert un texto con el SSID y la clave. El resultado es:



Esta imagen final contenida en el fichero wifi-key.png podemos difundirla de diversas maneras: publicarla en un servidor web, enviarla por correo a las cuentas interesadas o, como hago yo en el script anterior, subirla a Google Drive como fichero compartido. Previamente he compartido el enlace al fichero wifi-key.png con los usuarios que podrán consultar la clave.

Para subirla a Google Drive usamos el comando gdrive update, que sube y actualiza un fichero ya existente. El paso previo es subir la imagen a mano y compartirla. Eso nos dará un "id" que identifica el fichero y ese es el "id_googledrive" que usaremos en el script para posteriores actualizaciones.

Otros scrips que necesitamos son los que apagan y encienden la red wifi:
# cat /root/scripts/apagaWifi.sh 
#!/bin/bash
clave_router="claveopenwrt"
ip_openwrt="192.168.X.Y"
interface="1" #En mi caso la wifi está en el Interface 1.
comando="uci set wireless.@wifi-iface[$interface].disabled=1 ; uci commit wireless ; wifi"
sshpass  -p $clave_router ssh -o StrictHostKeyChecking=no root@$ip_openwrt "$comando"> /dev/null 2>&1

exit 0
Y:
# cat /root/scripts/enciendeWifi.sh 
#!/bin/bash
clave_router="claveopenwrt"
ip_openwrt="192.168.X.Y"
interface="1" #En mi caso la wifi está en el Interface 1.
comando="uci set wireless.@wifi-iface[$interface].disabled=0 ; uci commit wireless ; wifi"
sshpass  -p $clave_router ssh -o StrictHostKeyChecking=no root@$ip_openwrt "$comando" > /dev/null 2>&1

exit 0
Una vez tenemos los scripts, solo nos hace falta un cron para ejecutar las acciones de apagado, encendido y cambio de clave, en función de nuestras necesidades:
# cat /etc/cron.d/puntowifi
#Gestión de wifis . Se enciende por la mañana y se apaga por la noche. La clave cambia 5 veces al día.
00 24  * * *        root /root/scripts/wifi/apagaWifi.sh
30 11  * * *      root /root/scripts/wifi/enciendeWifi.sh
20 11,15,18,20,22  * * *      root /root/scripts/wifi/generaClaveWifi.sh  
22 11,15,18,20,22  * * *      root  /root/scripts/wifi/ponClaveWifi.sh 
Y con esto tenemos automatizado todo el proceso de cambio y difusión de la wifi. Así tendremos restringidos los accesos de una forma razonablemente sencilla.

Bueno, pues para hacer todo esto me he basado en esta entrada de blog, donde además viene muy bien explicado como hacerlo todo en el propio router OpenWRT, en lugar de usando una máquina externa como hemos explicado aquí.

Out!

Los camaradas chinos han lanzado esta semana la sonda Chang'e 5 que recogerá y traerá muestras de la Luna para fin de año:
Desde los años 70 no se hacía esto. Como vemos una vez más los chinos siguen avanzando hacia adelante mientras otros se dedican a dar vueltas sobre su estupidez.

martes, 17 de noviembre de 2020

Instalar OpenWrt en los puntos de acceso DLink DIR-860L

En todos los centros tenemos puntos de acceso DLink DIR-860L Modelo B1 que están siendo retirados al instalar las nuevas redes wifi. Originalmente vienen con el sistema operativo DD-WRT, que hasta ahora nos ha funcionado aceptablemente bien para el uso que les hemos dado.

El problema de DD-WRT es que es poco flexible, mientras que OpenWrt es mucho mas versátil: permite añadir y quitar paquetes de software, almacenar configuraciones y scripts fácilmente y tiene una comunidad de soporte enorme detrás.

Para cargar un nuevo firmware hay que poner el router en modo Recovery. Esto se hace apagando el router, presionando con un clip sobre el interruptor de reset que hay escondido en la base del mismo y encendiendo de nuevo el aparato. Tras 10-20 segundos el led de encendido comienza a parpadear. Soltamos el interruptor de reset.

Si abrimos el navegador y vamos a la dirección http://192.168.0.1 veremos esto:
Simplemente habria que seleccionar el fichero con el nuevo firmware, hacer Upload y esperar unos minutos a que se cargue y arranque.

¿Que firmwares OpenWrt podemos cargar? Veamos:

  • La primera opción es coger la última versión. En el momento de escribir esto era la 19.07.4. El problema es que una vez instalado he tenido problemas con la tarjeta wifi: se detectaba pero no funcionaba. Probando con otros firmwares mas antiguos como el 18.X o el 17.X no he tenido tampoco éxito. El fichero con el firmware estará en una ruta similar a esta:
    https://downloads.openwrt.org/releases/17.01.0/targets/ramips/mt7621/lede-17.01.0-r3205-59508e3-ramips-mt7621-dir-860l-b1-squashfs-factory.bin
  • Buscando en Internet encontré este post donde hay un desarrollo propio de imágenes para nuestro punto de acceso. Son imágenes que funcionan, pero están bastante cargadas de software y no son compatibles con los repositorios de paquetes oficiales, por lo que no es fácil instalar software adicional. No acababa de convencerme.
  • Encontré referencias a que las últimas versiones no van muy bien con la wifi, pero afortunadamente la 15.05.1 si que era plenamente operativa. Recomendamos pues descargar e instalar esta versión.


Una vez cargado el nuevo firmware, accedemos al interface web de configuración LuCI en la URL http://192.168.1.1. El primer paso definir una contraseña de root, para que se active la posibilidad de entrar por ssh en el dispositivo y realizar las siguientes configuraciones mediante líneas de comando o mediante LuCI, a nuestra elección.

Ya con OpenWRT cargado, ¿qué podemos hacer con los chismes?. Bueno, ideas:
  • Montar un punto wifi independiente para alguna cosa concreta. Es lo que se llama Routed AP.
  • Conectar el DLink con una red wifi preexistente y proporcionar conexión de red cableada desde alli. Es lo que se llama Routed Client.
  • Montar un repetidor wifi: no he probado si funciona.
  • Con una cámara USB montar una cámara IP.
  • Montar un sistema de USB sobre IP para conectar dispostivos USB remotos.
  • Montar un NAS pinchando un disco externo en el puerto USB.
  • Usarlo como dispositivo interpuesto físicamente para monitorizar el tráfico de red en algún punto que nos interese.
  • Con una tarjeta de sonido USB, usarlos como altavoces remotos para sistemas de hilo músical o megafonía.
  • .....
Vamos, que usos interesantes hay de sobra. Lo que nos falta es tiempo. Out!


Esto ya va siendo normal, pero no por ello menos emocionante: la cápsula Resilience de SpaceX se ha acoplado esta madrugada a la Estación Espacial Internacional. El anterior viaje en agosto fue un test, hoy era el primer vuelo regular con 4 cosmonautas:

Es curioso que apenas haya sido mencionado en las noticias, pero es a la vez un consuelo pensar que para los medios tradicionales los viajes de SpaceX son ya rutina. Esa es la idea: algún día los viajes a Marte en las sucesoras de las Falcon y Starship también serán rutina.

viernes, 13 de noviembre de 2020

Trabajando con polkit cuando los ficheros .pkla dejan de funcionar.

Usando polkit podemos permitir o prohibir a los usuarios determinadas acciones de configuración de partes del sistema.

Por ejemplo, para permitir a los usuarios del grupo "netdev" modificar conexiones wifi sin necesidad de contraseña de root distribuimos por puppet este fichero:
# cat /etc/polkit-1/localauthority.conf.d/10-org-freedesktop-network-manager-settings.pkla
[Allow group netdev create wireless connection for all users]
Identity=unix-group:netdev
Action=org.freedesktop.network-manager-settings.system.modify
ResultAny=no
ResultInactive=no
ResultActive=yes
Otro ejemplo, para impedir a los usuarios regulares reiniciar/suspender/apagar las máquinas de los espacios comunes usamos estas reglas:
# cat /etc/polkit-1/localauthority/50-local.d/disable-poweroff.pkla                                                             
[Disable power-off (logind)]
Identity=unix-user:*
Action=org.freedesktop.login1.power-off
ResultActive=no
ResultInactive=no
ResultAny=no

[Disable power-off when others are logged in (logind)]
Identity=unix-user:*
Action=org.freedesktop.login1.power-off-multiple-sessions
ResultActive=no
ResultInactive=no
ResultAny=no

# cat /etc/polkit-1/localauthority/50-local.d/disable-reboot.pkla                                                              
[Disable reboot (logind)]
Identity=unix-user:*
Action=org.freedesktop.login1.reboot
ResultActive=no
ResultInactive=no
ResultAny=no

[Disable reboot when others are logged in (logind)]
Identity=unix-user:*
Action=org.freedesktop.login1.reboot-multiple-sessions
ResultActive=no
ResultInactive

# cat /etc/polkit-1/localauthority/50-local.d/disable-suspend.pkla
[Disable suspend (logind)]
Identity=unix-user:*
Action=org.freedesktop.login1.suspend
ResultActive=no
ResultInactive=no
ResultAny=no

[Disable suspend when others are logged in (logind)]
Identity=unix-user:*
Action=org.freedesktop.login1.suspend-multiple-sessions
ResultActive=no
ResultInactive=no
ResultAny=no
Como vemos, todo consiste en meter un fichero .pkla en la ruta /etc/polkit-1/localauthority/50-local.d.

Hace poco, preparando unas máquinas con un Linux mas moderno (Manjaro LXDE 20) que el que usamos normalmente (Ubuntu 18 LTS) me he encontrado con que los ficheros .pkla son ignorados. Al parecer hasta polkit 0.105 funcionan, pero luego dejan de usarse y yo estaba trabajando con polkit 0.112. Como mas pronto que tarde tendremos este problema al subir de versión nuestro Ubuntu, mejor dejarlo ya anotado aquí para resolverlo cuando se nos presente.

Se trataba de tocar los permisos sobre org.freedesktop.NetworkManager.settings.modify.system, que son los referentes a modifcar conexiones de red del sistema. Veamos los permisos actuales usando el comando pkaction:
# pkaction -v -a org.freedesktop.NetworkManager.settings.modify.system
implicit any:      auth_admin_keep
implicit inactive: auth_admin_keep
implicit active:   auth_admin_keep
Están con el valor "auth_admin_keep", que significa que se pedirán permisos de root al realizar la acción org.freedesktop.NetworkManager.settings.modify.system. Mi intención es ponerlos todos a "no", ¿como se hace ahora que no hay ficheros pkla?. Pues hay dos vías:
  1. Modificar en el fichero /usr/share/polkit-1/actions/org.freedesktop.NetworkManager.policy el nodo org.freedesktop.NetworkManager.settings.modify.system:
        ....
        ....
        <defaults>
          <allow_any>no</allow_any>
          <allow_inactive>no</allow_inactive>
          <allow_active>no</allow_active>
        </defaults>
        ....
        ....
    
  2. O bien, dejar el fichero anterior sin tocar y escribir una regla en JavaScript tal como cuentan aquí:
    # cat /etc/polkit-1/rules.d/00-networkmanager.rules 
    polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.NetworkManager.settings.modify.system")
    {
        polkit.log("NetworkManager.settings.modify.system: rule called");
        return polkit.Result.NO;
    }
    });
    
    Otro ejemplo, para impedir la suspensión del equipo sería así:
    # cat /etc/polkit-1/rules.d/01-suspend.rules 
    polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.login1.suspend") {
        polkit.log("login1.suspend: rule called");
        return polkit.Result.NO;
    }
    });
    
    polkit.addRule(function(action, subject) {
    if (action.id == "org.freedesktop.login1.suspend-multiple-sessions")
    {
        polkit.log("login1.suspend-multiple-sessions: rule called");
        return polkit.Result.NO;
    }
    });
    
El segundo método me gusta más porque el fichero /usr/share/polkit-1/actions/org.freedesktop.NetworkManager.policy podría ser machacado en alguna actualización, mientras que las reglas son ficheros que creamos nosotros y no se borrarán.