jeudi 18 février 2016

libvirt QEMU : resize en live d'une partition (guest) basé sur un LV (host)

Pouet,

sur mon super NAS maison (un HP Proliant Microserver Gen8), j'ai un système principal à base de CentOS qui me sert d'hyperviseur (libvirt+QEMU), et j'ai des VM dont une sous OpenMediaVault (OMV) qui sert de NAS (fournit une GUI pour les partages, toussa). Sur mes 3 disques, les 2 gros servent au NAS (l'autre est en mode miroir pour un espace sécurisé), j'utilise le génial LVM pour partitionner les disques (et en réalité, des partitions aussi, car plusieurs VG).

Digression : je n'ai cependant pas profité de la fonctionnalité qui permet d'agréger des disques, c'est volontaire : lorsque les disques sont agrégés, c'est plus simple à l'usage car 1 seul FS, mais en cas de panne d'un des disques .. c'est effectivement tout cet unique FS qui est mort (et avec les bouts de fichiers probablement répartis partout sur les 2 disques, bonne chance pour une éventuelle récupération). J'ai donc 1 FS par disque, que OMV me permet d’agréger à l'aide de AUFS pour n'afficher qu'un FS à l'usage :).

Pour la VM OMV, je garde de l'espace dans le VG au cas où, et il m'arrive d'avoir besoin d'allouer de cet espace à OMV, seulement il faut agrandir le LV, puis relancer la VM, ce que je n'ai pas toujours envie de faire ; ça serait quand même plus cool de pouvoir le faire en live, non ? Surtout que QEMU permet ça lorsque le mode virtio est utilisé :).

Bref, assez de blabla, des commandes.

Agrandissement du LV sur l'host :

[root@equuleus ~]# pvs -o pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,lv_name,seg_start_pe,seg_size_pe,seg_start,seg_size,segtype,seg_pe_ranges
  PV         VG   Fmt  Attr PSize   PFree   LV                 Start SSize  Start  SSize   Type   PE Ranges
  /dev/sda3  sys  lvm2 a--  125.00g  72.00g root                   0   2500     0    9.77g linear /dev/sda3:0-2499
  /dev/sda3  sys  lvm2 a--  125.00g  72.00g home                   0   3750     0   14.65g linear /dev/sda3:2500-6249
  /dev/sda3  sys  lvm2 a--  125.00g  72.00g swap                   0   2018     0    7.88g linear /dev/sda3:6250-8267
  /dev/sda3  sys  lvm2 a--  125.00g  72.00g root_inst              0   2560     0   10.00g linear /dev/sda3:8268-10827
  /dev/sda3  sys  lvm2 a--  125.00g  72.00g root_sinst7            0   2510     0    9.80g linear /dev/sda3:10828-13337
  /dev/sda3  sys  lvm2 a--  125.00g  72.00g root                2500     60  9.77g 240.00m linear /dev/sda3:13338-13397
  /dev/sda3  sys  lvm2 a--  125.00g  72.00g root_sinst7         2510     50  9.80g 200.00m linear /dev/sda3:13398-13447
  /dev/sda3  sys  lvm2 a--  125.00g  72.00g swap                2018     30  7.88g 120.00m linear /dev/sda3:13448-13477
  /dev/sda3  sys  lvm2 a--  125.00g  72.00g home                3750     90 14.65g 360.00m linear /dev/sda3:13478-13567
  /dev/sda3  sys  lvm2 a--  125.00g  72.00g                        0  18431     0   72.00g free
  /dev/sda4  vm   lvm2 a--  125.00g  69.00g iso                    0   2560     0   10.00g linear /dev/sda4:0-2559
  /dev/sda4  vm   lvm2 a--  125.00g  69.00g images                 0   3840     0   15.00g linear /dev/sda4:2560-6399
  /dev/sda4  vm   lvm2 a--  125.00g  69.00g omv                    0   2560     0   10.00g linear /dev/sda4:6400-8959
  /dev/sda4  vm   lvm2 a--  125.00g  69.00g vm2                    0   2560     0   10.00g linear /dev/sda4:8960-11519
  /dev/sda4  vm   lvm2 a--  125.00g  69.00g t1                     0    256     0    1.00g linear /dev/sda4:11520-11775
  /dev/sda4  vm   lvm2 a--  125.00g  69.00g vm2_fresh              0   2560     0   10.00g linear /dev/sda4:11776-14335
  /dev/sda4  vm   lvm2 a--  125.00g  69.00g                        0  17663     0   69.00g free
  /dev/sda5  data lvm2 a--    2.48t 100.00g [secured_rmeta_2]      0      1     0    4.00m linear /dev/sda5:0-0
  /dev/sda5  data lvm2 a--    2.48t 100.00g [secured_rimage_2]     0 230400     0  900.00g linear /dev/sda5:1-230400
  /dev/sda5  data lvm2 a--    2.48t 100.00g                        0  25600     0  100.00g free
  /dev/sda5  data lvm2 a--    2.48t 100.00g nas-1                  0 395270     0    1.51t linear /dev/sda5:256001-651270
  /dev/sdb2  data lvm2 a--  931.51g  21.50g [secured_rmeta_0]      0      1     0    4.00m linear /dev/sdb2:0-0
  /dev/sdb2  data lvm2 a--  931.51g  21.50g [secured_rimage_0]     0 230400     0  900.00g linear /dev/sdb2:1-230400
  /dev/sdb2  data lvm2 a--  931.51g  21.50g nas-db                 0   2560     0   10.00g linear /dev/sdb2:230401-232960
  /dev/sdb2  data lvm2 a--  931.51g  21.50g                        0   5505     0   21.50g free
  /dev/sdc5  data lvm2 a--    5.21t 874.00g [secured_rmeta_1]      0      1     0    4.00m linear /dev/sdc5:0-0
  /dev/sdc5  data lvm2 a--    5.21t 874.00g [secured_rimage_1]     0 230400     0  900.00g linear /dev/sdc5:1-230400
  /dev/sdc5  data lvm2 a--    5.21t 874.00g                        0  25600     0  100.00g free
  /dev/sdc5  data lvm2 a--    5.21t 874.00g nas-2                  0 911361     0    3.48t linear /dev/sdc5:256001-1167361
  /dev/sdc5  data lvm2 a--    5.21t 874.00g                        0 198144     0  774.00g free

[root@equuleus ~]# lvextend data/nas-2 -L +174G /dev/sdc5
  Size of logical volume data/nas-2 changed from 3.48 TiB (911361 extents) to 3.65 TiB (955905 extents).
  Logical volume nas-2 successfully resized.

[root@equuleus ~]# pvs -o pv_name,vg_name,pv_fmt,pv_attr,pv_size,pv_free,lv_name,seg_start_pe,seg_size_pe,seg_start,seg_size,segtype,seg_pe_ranges
  PV         VG   Fmt  Attr PSize   PFree   LV                 Start SSize  Start  SSize   Type   PE Ranges
[..]
  /dev/sdc5  data lvm2 a--    5.21t 700.00g [secured_rmeta_1]      0      1     0    4.00m linear /dev/sdc5:0-0
  /dev/sdc5  data lvm2 a--    5.21t 700.00g [secured_rimage_1]     0 230400     0  900.00g linear /dev/sdc5:1-230400
  /dev/sdc5  data lvm2 a--    5.21t 700.00g                        0  25600     0  100.00g free
  /dev/sdc5  data lvm2 a--    5.21t 700.00g nas-2                  0 955905     0    3.65t linear /dev/sdc5:256001-1211905
  /dev/sdc5  data lvm2 a--    5.21t 700.00g                        0 153600     0  600.00g free

On informe le driver de la VM que le disque à changé de taille (attention aux unités, kb != kib) :

[root@equuleus ~]# virsh help blockresize
  NAME
    blockresize - Resize block device of domain.

  SYNOPSIS
    blockresize   

  DESCRIPTION
    Resize block device of domain.

  OPTIONS
    [--domain]   domain name, id or uuid
    [--path]   Fully-qualified path of block device
    [--size]   New size of the block device, as scaled integer (default KiB)


/!\ units ! (kb != kib) : 
[root@equuleus ~]# man lvs
[root@equuleus ~]# lvs data/nas-2 --units m
  LV    VG   Attr       LSize       Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  nas-2 data -wi-ao---- 3823620.00m

[root@equuleus ~]# virsh blockresize OMV /dev/data/nas-2 3823620m
Block device '/dev/data/nas-2' is resized

On check le syslog du guest : 

root@omv:~# dmesg
[3689800.752788] virtio_blk virtio7: new size: 7830773760 512-byte logical blocks (4.00 TB/3.64 TiB)
[3689800.752795] vde: detected capacity change from 3822525087744 to 4009356165120
[3689800.762729] VFS: busy inodes on changed media or resized disk vde


On lance le resize du FS (qui peut mettre plusieurs minutes, prévoir un screen/tmux pour cette étape serait pas mal) : 

root@omv:~# resize2fs -p /dev/vde
resize2fs 1.42.5 (29-Jul-2012)
Filesystem at /dev/vde is mounted on /media/211d3e2f-680f-4211-b597-203dcae5c756; on-line resizing required
old_desc_blocks = 446, new_desc_blocks = 467
Performing an on-line resize of /dev/vde to 978846720 (4k) blocks.
The filesystem on /dev/vde is now 978846720 blocks long.

lundi 10 mars 2014

Format de sous-titres ASS, édition et capacités

C'est en voulant regarder le film d'animation japonais The Garden of Words (言の葉の庭) que j'ai découvert quelques capacités du format de sous-titres SSA/ASS.
En fait, celui-ci n'existe qu'en VO ou VOSTEN, mais même si il est possible de trouver des sous-titres en français (pour ne pas perdre de temps à la lecture, ratant de ce fait les images magnifiques), on perd alors le joli style (enfin la police quoi) donné aux écritures.


Je suis donc parti dans l'adaptation de mon "pauvre" sous-titrage français au format SRT :
1
00:00:38,706 --> 00:00:42,084
Je ne connaissais pas ces choses-là
il y a encore deux mois,

2
00:00:42,334 --> 00:00:43,586
avant d'entrer au lycée.

vers le format ASS qui permet d'utiliser des polices :

[V4+ Styles]
Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding
Style: garden,LTFinnegan Medium,72,&H00FFF7E7,&H000000FF,&H00042419,&H00475244,0,0,0,0,100,100,0,0,1,3.5,2,2,15,15,65,1
[...]
[Events]
Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text
Dialogue: 0,0:00:38.70,0:00:42.08,garden,Unknown,0,0,0,,{\i1}Je ne connaissais pas ces choses-là\Nil y a encore deux mois,{\i0}
Dialogue: 0,0:00:42.33,0:00:43.58,garden,Unknown,0,0,0,,{\i1}avant d'entrer au lycée.{\i0}


D'abord, les sous-titres et les polices utilisées sont inclues dans le MKV.

> mkvmerge -i "The_Garden_of_Words.mkv"
Fichier 'The_Garden_of_Words.mkv' : conteneur : Matroska
Piste numéro 0 : video (V_MPEG4/ISO/AVC)
Piste numéro 1 : audio (A_FLAC)
Piste numéro 2 : subtitles (S_TEXT/ASS)
Pièce jointe numéro 1 : type 'application/x-truetype-font', taille 4654020 octets, nom de fichier 'A-OTF-Jun501Pro-Bold.
otf'
Pièce jointe numéro 2 : type 'application/x-truetype-font', taille 4796008 octets, nom de fichier 'G-OTF-GJun501Pro-Bold
.otf'
Pièce jointe numéro 3 : type 'application/x-truetype-font', taille 42980 octets, nom de fichier 'ITCGaramondStd-Bk.otf'
Pièce jointe numéro 4 : type 'application/x-truetype-font', taille 45940 octets, nom de fichier 'LegacySerifStd-Book.otf
'
Pièce jointe numéro 5 : type 'application/x-truetype-font', taille 62536 octets, nom de fichier 'LT.ttf'
Pièce jointe numéro 6 : type 'application/x-truetype-font', taille 62480 octets, nom de fichier 'LT_3italic.ttf'
Pièce jointe numéro 7 : type 'application/x-truetype-font', taille 58700 octets, nom de fichier 'PPETRIAL.otf'
Pièce jointe numéro 8 : type 'application/x-truetype-font', taille 109200 octets, nom de fichier 'PPETRIAL.ttf'
Pièce jointe numéro 9 : type 'application/x-truetype-font', taille 172732 octets, nom de fichier 'segoepr.ttf'
Pièce jointe numéro 10 : type 'application/x-truetype-font', taille 35752 octets, nom de fichier 'TheGreatEscape.ttf'
Pièce jointe numéro 11 : type 'application/x-truetype-font', taille 93152 octets, nom de fichier 'Thin Pencil Handwritin
g.otf'
Pièce jointe numéro 12 : type 'application/x-truetype-font', taille 3419056 octets, nom de fichier 'epsonthora.ttf'

Il est possible de tout extraire, mais seul le fichier de sous-titres ASS est utile :

> mkvextract tracks "The_Garden_of_Words.mkv" 2:en.ass
Extraction de la piste 2 avec le codec 'S_TEXT/ASS' dans le fichier 'en.ass'. Format de conteneur : SSA/ASS text subtitles
Progression : 100%

Ensuite commence le travail. J'ai choisi de conserver les temps du sous-titrage français, principalement parce que j'ai pu remarquer qu'a plusieurs endroits la découpe des dialogues est faite différemment.
Une dizaine de regex dans Notepad++, quelques corrections de bugs (nombre de décimales), on rajoute les en-têtes du ASS d'origine et hop : le SRT devient un ASS, le principal est fait.

Mais le fichier ASS d'origine contient plus que des dialogues, j'ai pu m'en rendre compte en comparant l'original à mon ASS modifié dans WinMerge. Une des grosse différence sert en fait .. à générer un texte animé lors du titre principal !


Pour le reste, il s'agit en fait de texte incrusté, et si on ne le sait pas, il est facile de passer à côté.

Quelques exemples :

  • "June"



Et d'autres sont vraiment cachés :

  • l'examen

  • les noms sur le portable ...
Il a donc fallu traduire ces textes aussi, cette fois manuellement, et ça aura aussi permis de supprimer quelques traductions en trop comme "Juin" qui étaient présentes dans le SRT.

Le plus gros travail aura été la chanson de fin, puisqu'il a fallu faire un découpage correct des textes pour remplacer la traduction existante.

Enfin, je me suis essayé à incruster une des traduction du SRT dans l'image, comme le fait le ASS, voila la résultat :

En bref, j'ai été impressionné de voir les capacités des formats actuels de sous-titrage, adapter une traduction aura été un exercice sympa.

 「鳴る神の 少し響みて さし曇り 雨も降らぬか 君を留めむ」

La traduction au format ASS : https://drive.google.com/file/d/0B63FLnZuVDrvVGcweHlEakhhNlE

Annexes : 
http://matroska.org/technical/specs/subtitles/ssa.html
http://pireze.org/2013/anime-review-makoto-shinkais-the-garden-of-words-%E8%A8%80%E3%81%AE%E8%91%89%E3%81%AE%E5%BA%AD-kotonoha-no-niwa/
http://mlr.inktails.com/2013/07/jp-movie-the-garden-of-words-2013/
http://louvreuse.net/critique/the-garden-of-words.html
http://www.imdb.com/title/tt2591814
http://www.subsynchro.com/2012/the-garden-of-words.html ("Byousuku 5 Centimeters" semble sympa à voir aussi)

dimanche 19 janvier 2014

Hacking du module hid-wiimote pour fonctionner avec le Pro Controller U sous RetroPie

Introduction

Aujourd'hui, un article qui risque d'être assez long (et très probablement assez mal écrit) pour revenir sur mon activité de ces derniers jours.


Avant de commencer, le contexte : la plateforme RaspberryPi est équivalente à un téléphone portable et permet de faire de l'émulation de consoles grâce à des distributions comme RetroPie (utilisant RetroArch, un des seul émulateur pi basé sur Pico capable de faire tourner certains jeux de Megadrive, comme Sonic Spinball, et EmulsationStation pour proposer une interface de lancement des jeux). Il existe aussi Chameleon et PiMAME, mais malheureusement l'émulateur Megadrive qui y est intégré ne fonctionne pas avec tout les jeux.

J'ai pu valider cette partie, et tester avec une manette bas de gamme (moyennant quelques configurations à la main pour EmulationStation et RetroArch).
Maintenant il peut être intéressant de pouvoir jouer à 2, et donc connecter 2 manettes, mais :
  • les fils, c'est chiants
  • la Pi n'aime pas trop se faire tirer du courant, ça la fait planter

D'où cette idée : acheter un dongle bluetooth et utiliser des manettes sans fil. J'en ai commandé 2 sur Amazon : 

Cette première n'est absolument pas Bluetooth contrairement à ce qu'indique son nom .. Il faut utiliser leur gros dongle .. Amazon va la récupérer.
L'autre manette est celle ci :
Qui n'est pas une manette WiiU Pro contrairement à ce qu'indique son nom, mais une Wii Classic Controller Pro (qui fait aussi Wiimote simple).
Elle fonctionne en bluetooth comme les manettes Wii, on peut donc en associer plusieurs sur un simple dongle bluetooth.

Première approche

Ma première approche a été d'utiliser les tutos disponibles sur internet, tel que :
Ils se basent sur cwiid couplé avec wminput pour gérer les boutons. Seulement .. avec cette manette, ça ne fonctionne pas, il y a des messages d'erreur ("Received unexpected write report") et la partie Classic (il y a un switch sur la manette) fait comme si aucune touche n'était pressée. J'ai tenté de compiler la derniere version de cwiid, qui m'a permit de jouer avec les leds, mais pas plus.

J'ai fait d'autres recherche et suis tombé sur quelques liens : 
Il a fallu compiler wiiuse (je passe les détails, c'est expliqué), mais je n'ai pas eu beaucoup plus de succès.

J'ai songé à un moment à parser les messages de la manette à la main, en prenant la méthode suitante : http://smus.com/prototyping-wii-remote-python/ mais quand un rapide test montre que la manette balance des 0xFF en continu, c'est qu'il faut lui envoyer les bonnes données avant, et bon .. flemme.

L'approche xwiimote / hid-wiimote

C'est en faisant des recherche sur la WiiU Pro Controller que j'ai vu qu'il existait une manette pour WiiU, qui n'est donc pas la même, et qu'il existe des logiciels pour l'utiliser (mais la mienne n'est pas celle-ci, même si je l'ai cru à un moment, le nom de la manette prêtant à confusion) : 
XWiimote is an open-source linux device driver for Nintendo Wii / Wii U Remotes and compatible devices. It is a relatively new driver that tries to supercede cwiid, wiiuse and others by integrating the driver into existing linux infrastructure. The project consists of an official linux kernel driver, which is part of the kernel since linux-3.1, an extension to bluez, the official linux bluetooth stack, an X11 input driver, some user-space helpers and test applications.
Surprise donc ! Il existe un module kernel, qui se prétend mieux que cwiid et wiiuse, et qui se trouve être présent dans RetroPie (kernel 3.6.11+). Il y a même un super programme qui affiche les touches de la Wiimote et ses extensions en ASCII (xwiishow) !
(tiré de http://leftbraintinkering.blogspot.fr/2014/01/wii-remote-plus-and-linux.html)
Mais après compilation de xwiishow, malheureusement même constat, le Classic controller ne fonctionne pas :(. Je commence à penser que la manette est défectueuse.
A noter qu'il faut utiliser hidd pour associer la Wiimote, bluez demandant un PIN.

Hack de hid-wiimote

Ayant jeté un œil aux sources du module hid-wiimote, et n'ayant plus rien à perdre (a part renvoyer la manette, mais elle me plait vraiment avec sa forme à la SuperNES), je me lance dans la modification de ce module.
Il faut pour ça pouvoir compiler, sur une Pi contrairement aux petits logiciels d'avant, c'est impensable, il faut donc passer par de la cross-compilation. l'avantage avec la Pi c'est qu'il existe plein de docs/tutos, on trouve donc des instructions pour cela : http://elinux.org/RPi_Kernel_Compilation.
Une VM Ubuntu x64, les libs pour exécuter des programmes x86, puis il suffit de suivre les instructions :

KERNEL_SRC=/home/user/raspbian-kernel/linux-rpi-3.6.y/
CCPREFIX=/home/user/raspbian-kernel/tools-master/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-
make mrproper
make ARCH=arm CROSS_COMPILE=${CCPREFIX} oldconfig
make ARCH=arm CROSS_COMPILE=${CCPREFIX}
make ARCH=arm CROSS_COMPILE=${CCPREFIX} modules

A noter qu'il faut compiler le kernel (make) avant de compiler les modules (make modules), sinon :
ERROR: could not insert 'hid_wiimote': Exec format error

Reconnaissance du Classic Controller

Le principal problème étant que l'extensions Classic n'est pas reconnu, alors qu'a priori présente, je décide de la forcer :
  wmem = 0x55;
  wiimote_cmd_write(ext->wdata, 0xa400f0, &wmem, sizeof(wmem));
  wmem = 0x0;
  wiimote_cmd_write(ext->wdata, 0xa400fb, &wmem, sizeof(wmem));
  return WIIEXT_CLASSIC;
Et la, même si rien n'est reconnu ou fonctionnel dans xwiishow, evtest affiche bien des boutons en mode Classic !
Mais le stick gauche ne fonctionne pas en vertical et les triggers font 2 actions au lieu d'une.

Debug des controles

Pour voir ce qu'envoi la manette, j'essaye un débogage (comme je peux, le debugging de kernel je connais pas), c'est sale (mais fonctionnel) :
#define BYTETOBINARYPATTERN "%d%d%d%d%d%d%d%d"
#define BYTETOBINARY(byte)  \
  (byte & 0x80 ? 1 : 0), \
  (byte & 0x40 ? 1 : 0), \
  (byte & 0x20 ? 1 : 0), \
  (byte & 0x10 ? 1 : 0), \
  (byte & 0x08 ? 1 : 0), \
  (byte & 0x04 ? 1 : 0), \
  (byte & 0x02 ? 1 : 0), \
  (byte & 0x01 ? 1 : 0) 
  
  
  printk(KERN_INFO "Byte %d "BYTETOBINARYPATTERN"", 0, BYTETOBINARY(payload[0]));
  printk(KERN_INFO "Byte %d "BYTETOBINARYPATTERN"", 1, BYTETOBINARY(payload[1]));
  printk(KERN_INFO "Byte %d "BYTETOBINARYPATTERN"", 2, BYTETOBINARY(payload[2]));
  printk(KERN_INFO "Byte %d "BYTETOBINARYPATTERN"", 3, BYTETOBINARY(payload[3]));
  printk(KERN_INFO "Byte %d "BYTETOBINARYPATTERN"", 4, BYTETOBINARY(payload[4]));
  printk(KERN_INFO "Byte %d "BYTETOBINARYPATTERN"", 5, BYTETOBINARY(payload[5]));
Et ça donne pleiiiiin de lignes dans les logs :
Jan 17 17:16:52 raspberrypi kernel: [65820.154165] Byte 1 00100000Byte 2 00010000
Jan 17 17:16:52 raspberrypi kernel: [65820.154198] Byte 3 00000000Byte 4 11111111
Jan 17 17:16:52 raspberrypi kernel: [65820.154221] Byte 5 11111111Byte 0 10100000
Jan 17 17:16:52 raspberrypi kernel: [65820.161071] Byte 1 00100000Byte 2 00010000
Jan 17 17:16:52 raspberrypi kernel: [65820.161100] Byte 3 00000000Byte 4 11111111
Jan 17 17:16:52 raspberrypi kernel: [65820.161121] Byte 5 11111111Byte 0 10100000
Comme je disais, c'est sale, mais ça fonctionne et permet de repérer doucement les touches, je me suis alors construit une carte :
Byte 0 10100000
       ^^-------RX(12)
         ^^^^^^-LX

Byte 1 00100000
       ^^-------RX(34)
         ^^^^^^-LY

Byte 2 00010000
       ^--------RX(5)
        ^^------TL
          ^^^^^-RY


Byte 3 00000000
       ^^^------TL
          ^^^^^-TR

Byte 4 11111111
       ^--------RIGHT
        ^-------DOWN
         ^------BTL
          ^-----MINUS
           ^----HOME
            ^---PLUS
             ^--BTR
              ^-1

Byte 5 11111111
       ^--------TL2
        ^-------B = ZL
         ^------Y
          ^-----A
           ^----X = ZR
            ^---TR2
             ^--LEFT
              ^-UP

Corrections

Il s'avère que cela correspond aux indications dans les sources de hid-wiimote .. C'est donc ailleurs que se situe le problème. Entre temps je tombe sur les sources du module pour le kernel 3.11, qui sont corrigées
                lx = payload[0] & 0x3e;
                ly = payload[0] & 0x3e;
lx = ly ? Oui, il y a comme un problème.
Il y a aussi une double négation sur les touches qui fait qu'elle apparaissent comme pressées en permanence, c'est corrigé aussi.

J'en profite aussi pour modifier les touches du D-Pad pour mapper des boutons au lieu des touches UP/DOWN/LEFT/RIGHT, qui ne sont pas reconnues par retroarch-joyconfig.
Enfin il y a un dernier bug qui est apparu quand j'ai voulu tester l'utilisation avec 2 wiimotes (voir si les leds sont gérées .. la réponse est non), qui nécessite de supprimer l'intégration du report des informations batterie dans le kernel, sinon il tente de créer 2 fois le même périphérique, et alors :
[178790.876742] ------------[ cut here ]------------
[178790.876794] WARNING: at fs/sysfs/dir.c:536 sysfs_add_one+0x88/0xc0()
[178790.876810] sysfs: cannot create duplicate filename '/class/power_supply/wiimote_battery'
[...]
[178790.883777] ---[ end trace 66509376675ee1a0 ]---
[178791.878245] power_supply wiimote_battery: driver failed to report `capacity' property: 4294967291
[178791.878349] wiimote 0005:057E:0306.0015: Cannot register battery device
[178792.882087] wiimote: probe of 0005:057E:0306.0015 failed with error -17

Bref, l'ensemble des modification est visible ici :
https://github.com/Alex131089/raspberrypi-linux/compare/raspberrypi:rpi-3.6.y...rpi-3.6.y-hid-wiimote

Conclusion

Bien que je ne soit pas entré dans le détail, j'ai une petite vue du fonctionnement des Wiimote, et de la gestion au niveau du kernel. Première expérience de cross-compilation aussi, merci au projet RaspberryPi qui a préparé les outils.

Ma manette est donc fonctionnelle, il reste à tester en condition réelle, mais les contrôles semblent tous reconnus cette fois. Il reste à créer un script qui pourra scanner une liste de commande (hidd --connect) ou toute commande (hidd --search) pour s'y connecter, qui scannera en permanence, et qui affectera les bonnes leds (p1, p2) aux commandes, à coup de recherche dans /sys/class ^^

Je joins aussi mon fichier de "travail" qui contient moulte liens sur lesquels je suis tombé pendant mes recherches.

lundi 17 juin 2013

Script Linux pour s'assurer de la connectivité

Aujourd'hui, un petit script pour s'assurer de la connectivité IPv4 et IPv6 sur une interface qui ne récupère pas toujours ses adresses (vivent le wifi, une ipw2200).

On ecrit le script qui fait le check :
[root@Virgo ~]# cat /etc/perso-wifi.sh
#!/bin/bash

INTF=wlp1s5

IP4=$(ip addr show dev $INTF scope global primary | grep -c "inet ")
IP6=$(ip addr show dev $INTF scope global primary | grep -c "inet6 ")

echo "IPv4 : $IP4 / IPv6 : $IP6"
if [ "$IP4" -lt "1" -o "$IP6" -lt "1" ]; then
  nohup systemctl restart netctl-auto@$INTF.service >/dev/null 2>&1 &
fi

Il regarde les adresses de connectivité globale et primaire (il peut y en avoir plusieurs, surtout en IPv6 si use_tempaddr est utilisé, dans mon cas je veux que l'adresse principale soit présente) et compte leur nombre pour IPv4 et IPv6. Si il n'y en a pas pour une des connectivité, il y a un problème et le script demande au système de relancer la connexion sur cette interface (en fond de tache pour ne pas garder le la tache cron et sans interruption quand le cron quitte).

On active ensuite le service de cron :

systemctl enable cronie.service
systemctl start cronie.service

Puis on y ajoute le script créé qui sera exécuté toutes les 5 minutes :

[root@Virgo ~]# crontab -l
*/5 * * * * /etc/perso-wifi.sh

Et voila, la machine est normalement joignable sur ses 2 connexions même en cas d'échec.
Notez que je ne vérifie pas qu'internet est joignable (inutile de relancer la connexion si c'est la box qui fail) ni si la box est joignable (idem), juste qu'on nous a bien donné des adresses, ce qui n'est pas toujours le cas au reboot (wpa_supplicant se rate souvent), et qui fait perdre la main.

dimanche 19 mai 2013

fun_plug sur clé USB pour D-Link DNS-320LW

Comme moi, vous avez peut-être profité de l'offre de TopAchat proposant un NAS D-Link DNS-320LW + 2x2To (soit 4To) à 200€ (soit le prix des 2 disque sur, en fait).
De base, le NAS propose déjà pas mal de fonctions (FTPS, SMB, NFS, DLNA, des droits suffisamment fin, JBOD, interface de téléchargement, et j'en passe pas mal), mais il est possible (merci à D-Link pour cela) d'augmenter encore ses capacités !

Une petite information au passage, parce que j'ai cherché moi aussi : matériellement, la version 320L (et W pour white of course) est très proche du 320, mais possède le double de mémoire (256Mo) et un processeur de 1Ghz (contre 800MHz). Le firmware semble être vraiment différent cependant, peut-être pas au niveau de l'interface, mais le 320 en est à la 2 alors que le 320L à la 1.

Revenons à ce qui nous intéresse : fun_plug (ffp). Grâce à D-Link, il est possible d’exécuter un script au démarrage du NAS, parce que si un fichier fun_plug est présent sur le volume 1, il est appelé à la fin du démarrage, justement pour tolérer ce fonctionnement. Des gens ont donc compilé des binaires fonctionnants sur le NAS et on peut retrouver un vrai petit environnement Linux.

Dans le fonctionnement de base, un place fun_plug et une archive fun_plug.tgz à la racine du volume 1, au 1er boot celle-ci est décompressé puis supprimé et offre un accès telnet, ce fut ma 1ère tentative (en passant par l'interface web d'envoi de fichier, qui own les fichier en root:root et mode en 777). Bien, on retrouve un accès root, un shell, c'est gagné.

Mais au reboot, le 320L devient chiant car un effectue un chmod 777 -R sur tout les volumes, nos fichiers (ah oui au fait, en interne c'est de l'ext4) perdent donc leurs modes et par exemple :
  • tout les scripts de /ffp/start/ (le init.d de ffp) sont +x, les services se retrouvent tous lancés au 2ème reboot
  • les fichiers clés d'sshd sont aussi en 777, accès libre pour tous, et comme sshd n'aime pas cela, il refuse de se lancer, plus de ssh, ou renvoi des erreurs dans les logs.
Autre petit souci, les scripts/binaires étant situés sur les disque dur, cela oblige ces derniers à être relancés régulièrement, on perd une partie du coté "éco". Il est possible de placer fun_plug sur une clé USB, et c'est ce que je vais expliquer (du moins, à ma façon). Arrivé ici, j'ai déjà un fun_plug installé sur le disque dur, rebooté seulement pour son installation (avant le 2ème reboot qui chmod tout), avec juste le telnet. Sur le 320L, la clé USB est monté sur /mnt/USB/USB_c1 (il faut adapter).

Formater la clé USB

umount /dev/sdxx
fdisk /dev/sdx
d
c
p
1
w
mkfs.ext4 -O ^has_journal -E stride=2,stripe-width=1024 -b 4096 /dev/sdxx
En me fiant à http://blogofterje.wordpress.com/2012/01/14/optimizing-fs-on-sd-card/ pour les options de formattage car ma clé USB est en fait un lecteur de carte, mais je pense que ça s'applique de la même façon à une "vrai" clé USB.

Installer fun_plug dessus

cd /mnt/USB/USB1_c1
wget http://ffp.inreto.de/ffp/0.7/arm/fun_plug.tgz
tar xzf fun_plug.tgz -C ffp/
/ffp/bin/tar xzf fun_plug.tgz -C ffp/

Utiliser un fun_plug compatible USB

J'ai utilisé ce fun_plug (venant d'ici) qui est une variante de l'original a peine modifié (je préfère) pour fonctionner en USB lorsque c'est possible. Le fichier fun_plug lui reste sur le volume 1 (c'est ici que le firmware le cherchera), mais tout le dossier /ffp/ sera situé sur la clé USB. Celle-ci se trouve d'ailleurs dans /mnt/USB/USB_c1/ et non HD_c1, il faut donc modifier le fichier fun_plug : 
sed -ie 's#USB/HD_c1#USB/USB1_c1#g' /mnt/HD/HD_a2/fun_plug
Je l'ai aussi modifié pour qu'il remonte la clé USB en noatime et nodiratime (qui feraient trop d'accès sur la clé) et sauve une copie du dmesg au boot, au final on obtient ceci : 

#!/bin/sh

# switch to safe working directory on ramdisk
cd /

# fichier de trace
exec >>/mnt/HD/HD_a2/ffp.log 2>&1

# Bootlog
dmesg > /var/log/boot.log

# Activation de autoboot USB (O ou N)
AUTOBOOT_USB=O
# Emplacement du repertoire FFP
FFP_USB_DRIVE=/mnt/USB/USB1_c1
FFP_PATH_USB=$FFP_USB_DRIVE/ffp
FFP_PATH=/mnt/HD/HD_a2/ffp

# Si on utilise ffp sur USB et qu'elle est présente, on change les options de montage
if [ "$AUTOBOOT_USB" = "O" ] && [ -d $FFP_PATH_USB ]; then
  FFP_PATH=$FFP_PATH_USB
  mount -o remount,noatime,nodiratime $FFP_USB_DRIVE
fi

# where to search for the install tarball
FFP_TARBALL=/mnt/HD/HD_a2/fun_plug.tgz

# rc file path
FFP_RC=/ffp/etc/rc

echo "**** fun_plug script for DNS-320/325  ****"
echo "Demarrage sur $FFP_PATH"
date

# create /ffp link
echo "ln -snf $FFP_PATH /ffp"
ln -snf $FFP_PATH /ffp

# install tarball
if [ -r $FFP_TARBALL ]; then
    echo "* Installing $FFP_TARBALL ..."
    mkdir -p $FFP_PATH && tar xzf $FFP_TARBALL -C $FFP_PATH && /ffp/bin/tar xzf $FFP_TARBALL -C $FFP_PATH
    if [ $? -eq 0 ]; then
        echo "* OK"
    fi
    rm $FFP_TARBALL
fi

# suid busybox
if [ -x /ffp/bin/busybox ]; then
    chown root.root /ffp/bin/busybox
    chmod 0755 /ffp/bin/busybox
    chmod u+s /ffp/bin/busybox
fi

# run fun_plug.init, if present
if [ -x /ffp/etc/fun_plug.init ]; then
    echo "* Running /ffp/etc/fun_plug.init ..."
    /ffp/etc/fun_plug.init
fi

# run fun_plug.local, if present
if [ -x /ffp/etc/fun_plug.local ]; then
    echo "* Running /ffp/etc/fun_plug.local ..."
    /ffp/etc/fun_plug.local
fi

# run commands
if [ -x $FFP_RC ]; then
    echo "* Running $FFP_RC ..."
    $FFP_RC
    echo "*  OK"
else
    echo "$FFP_RC: Not found or not executable"
fi

Empêcher le chmod 777

Comme je disais, le NAS effectue un bon gros chmod 777 sur tout les volumes, cela inclut la clé USB, il faut modifier un peu le système pour l'empêcher d'effectuer ceci au moins sur la clé USB, on commence par créer le fichier qui remplace chmod : 
cd /usr/local/config/
vi chmod_usb.sh

#!/bin/sh

# log everything to a file
exec >>/usr/local/config/chmod.log 2>&1

args="$@"
NOW=$(date +"%Y-%m-%d %T")
HD=USB1_c1

#these are the chmod args we want to suppress
suppress_args="777 -R /mnt/USB/$HD"

if [ "$args" != "$suppress_args" ]; then
    echo "[$NOW] Executing chmod $args"
    /bin/busybox chmod $@
else
   echo "[$NOW] Suppressing chmod $args"
fi
Suivi d'un chmod 777 chmod_usb.sh

Puis on effectuera le "remplacement" à chaque démarrage grâce au rc.init.sh (on conserve une copie du init.rc) :

cd /usr/local/config/
cp -pf rc.init.sh rc.init.sh.orig
echo "# USB chmod Patch" >>rc.init.sh
echo "[ -x /usr/local/config/chmod_usb.sh ] && ln -nfs /usr/local/config/chmod_usb.sh /bin/chmod">>rc.init.sh

On peut effectuer le ln -nfs /usr/local/config/chmod_usb.sh /bin/chmod et s'assurer que la commande chmod fonctionne toujours.

Supprimer fun_plug du disque dur

Dans mon cas, je ne veux pas que fun_plug puisse fonctionner sur le disque dur, seulement la clé USB, la solution est donc simple et à effectuer avant le redémarrage qui lancera fun_plug depuis la clé USB : 
rm -rf /mnt/HD/HD_a2/ffp/

On peut redémarrer le NAS, on devrait retrouver l'accès telnet au bout de 2-3 minutes mais cette fois avec un fun_plug contenu dans la clé USB !

Personnaliser SSH

Un des avantages de fun_plug est d'avoit un accès SSH au NAS, il y a cependant quelques modifications à effectuer (maintenant et pas avant car on modifie des fichiers de la clé) ; pour ma part j'utilise une clé privé pour me connecter en SSH, je laisse donc le mot de passe root intouché (ie. vide), mais ce n'est pas gênant.

mkdir -p /ffp/home/root/.ssh
chmod og-w -R /ffp/home/root/.ssh
vi authorized_keys
cd /usr/local/config
sed -ie 's#:/home/root:#:/ffp/home/root:#g' passwd
sed -ie 's#root:/bin/sh#root:/ffp/bin/sh#g' passwd
cd /etc
cd /usr/local/config
sed -ie 's#:/home/root:#:/ffp/home/root:#g' passwd
sed -ie 's#root:/bin/sh#root:/ffp/bin/sh#g' passwd
pwconv

On défini la/les clés ssh autorisés pour le compte root, puis on modifie le HOME (c'est ici que sshd cherchera les clés) et le shell (pour un beau bash) de root dans le dossier permanent (/usr/local/config qui est dans la flash du NAS) et dans le dossier chargé actuellement (pour éviter un reboot), on assure la prise en compte avec un pwconv.

Ah, il faut aussi changer un petit test dans /ffp/start/sshd.sh car il y a une référence à /etc/ssh et non /ffp/etc/ssh.

Enfin j'assure la sécurité en modifiant /ffp/etc/ssh/sshd_config

PermitRootLogin yes
PermitEmptyPasswords no
# Perso
AllowUsers root Alex

Root peut se connecter, pas de mot de passe vide possible (ça tombe bien, celui de root est vide, on ne pourra donc utiliser que la clé privé). Enfin seul root et Alex peuvent faire du SSH (si un utilisateur à un mot de passe faible, il pourrait offrir un accès SSH, on limite donc).

Enfin on peut lancer SSH : 

chmod +x /ffp/start/sshd.sh
/ffp/start/sshd.sh start

On peut de nouveau redémarrer le NAS, on attend 2-3 minutes puis on s'assure de l'accès SSH. Si c'est ok, on peut couper telnet : 

/ffp/start/telnetd.sh stop
chmod -x /ffp/start/telnetd.sh

Et voila !
Je n'ai pour l'instant pas été beaucoup plus moins, mais j'ai déjà un accès ssh root, tout est donc possible à partir de maintenant :)
Oh, et le NAS est parfaitement compatible IPv6 (l'interface web aussi !).

Quelques liens



jeudi 9 mai 2013

Mises à jour Windows Defender automatiques sous Windows 8

Je n'utilise pas le paramètre recommandé "Installer les mises à jour automatiquement" pour Windows Update, principalement parce que celui-ci génère un message invitant à redémarrer le PC lorsque des mises à jour le demandent.
C'est donc "Télécharger les mises à jour mais me laisser choisir s'il convient de les installer" que j'utilise. Un des effets de ce paramètre est que les mises à jour Windows Defender, proposant chaque jour un nouveau fichier de définitions, ne sont pas non plus installées et je suis donc invité chaque jour à les installer ... Enfin j'étais.


Le problème était le même sous Windows 7 et j'avais trouvé le "truc", et visiblement sous Windows 8 certaines personnes cherchent aussi comment faire :

Ma solution ne permet pas d'avoir les mises à jour "manuelles" mais seulement d'avoir les mises à jour majeures en manuel (celles qui demandent un redémarrage), les mineures comme les définitions de Defender seront automatiques.

Cela consiste donc à : 
  • mettre le paramètre sur "Télécharger les mises à jour mais me laisser choisir s'il convient de les installer" pour toutes les autres
  • et pour les mineures, ajouter une clé dans le registre dans :
    HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate\AU
    créez une valeur DWORD "AutoInstallMinorUpdates" avec la valeur 1
    (Doc WSUS : http://technet.microsoft.com/en-us/library/dd939844(v=ws.10).aspx)
Cette clé autorise donc l'installation automatique des mise à jour ne nécessitant pas de redémarrage.
On retrouve aussi ce paramètre dans gpedit.msc (Windows Components/Windows Update).

Mises à jour automatiques : oui, mais sans être dérangé (cette option devrait être disponible tiens).

Migrer ses jeux Steam lors d'une réinstallation

Besoin de réinstaller ou changer de PC, mais pas envie de re-télécharger 150Go de jeux Steam ?
C'est possible, et sans utiliser la fonction d'exportation des jeux (qui plante en plus) :).


Les étapes :
  • Faire une copie du dossier SteamApps qui se trouve dans le dossier de Steam (C:\Program Files (x86)\Steam par exemple) vers la nouvelle destination (lecteur, mais pas le dossier final)
  • Supprimer les fichiers appmanifest_<id-jeu>.acf qui s'y trouvent : il est possible de les conserver, mais alors Steam n’exécutera pas les actions effectuées au 1er lancement et qui peuvent être nécessaires (installation d'OpenAL, création de clés dans le registre, définition de l'emplacement des executables, ...)
  • Réinstaller Steam (SteamInstall.msi demande la langue à utiliser) à l'emplacement voulu (qui peut-être dans Program Files, mais aussi sur une autre partition)
  • Le lancer, attendre les mises à jour du client, le fermer complètement
  • Remettre le dossier SteamApps en place dans le nouveau dossier d'installation de Steam
    Note : depuis une mise à jour, il est possible pour certains jeux (les non-steam principalement) de les installer à un autre emplacement, il suffit alors d'indiquer dans les préférences cet emplacement pour ces jeux.
  • Relancer Steam, attendre plusieurs minutes pour les jeux qu'il détecte tout seul, pour les autres il suffit de lancer la demande d'installation, il va alors découvrir les fichiers déjà présents sur le disque et les valider ; normalement il ne lui reste quasiment rien à télécharger
  • Voilà, les jeux sont de nouveaux disponibles en quelques heures et non en quelques jours de téléchargement :)