Thursday, 17 January 2019
Écrit par
Grégory Soutadé

After further investigations, I found a correct fix to this. In facts, its my configuration that is wrong. I have LUKS on LVM schema like this :

system_group (LVM)
    --> system_crypt (LUKS)
swap_group (LVM)
    --> swap_crypt (LUKS)
home_group (LVM)
    --> home_crypt (LUKS)

To be right handled, you need to declare :

In /etc/crypttab :

home--group-home_crypt UUID=349ca075-2922-4c9c-a52b-8dce587767ea /root/home.key luks
swap--group-swap_crypt UUID=4490ce3c-8700-4e90-81df-250cd3573b7c /root/swap.key luks
system--group-system_crypt UUID=95e39100-25c2-41be-829a-bd84fcb21d0a none luks

use blkid command to get right UUID values

In /etc/fstab :

/dev/mapper/system--group-system_crypt /           ext4    errors=remount-ro 0       1
UUID=6866a661-0424-472c-853e-6daa20d15d74 /boot    ext4    defaults          0       2
/dev/mapper/home--group-home_crypt /home           ext4    defaults          0       2
/dev/mapper/swap--group-swap_crypt none            swap    sw                0       0

In /etc/initramfs-tools/conf.d/resume :


Then, do sudo update_initramfs -u and restart.

It's the second time it happens ! After an update my Debian refuse to boot. This time, I wasn't asked for anything !!

I have an LUKS on LVM configuration. I don't use UUID in my cryptroot and Debian scripts only activate devices with it ! I need to manually add "vgchange" command to mount all devices. Unfortunately, the patched script was overwrote by update.

If it happens, follow this procedure :

  • At boot, wait for the rescue shell (~5 minutes)
  • Enter "vgchange -ay"
  • Enter "exit"

Now, you may be able to boot into your system. Then :

  • Edit /usr/share/initramfs-tools/scripts/local-top/cryptroot
  • Add "vgchange -ay" in wait_for_source() function
  • Update initramfs with "sudo update-initrmafs -u"

Safely reboot !

Monday, 06 August 2018
Écrit par
Grégory Soutadé

Here is a simple tip to use keyctl in a bash script. keyctl is a wrapper for Linux kernel key management interface. It allows to securely save data in kernel memory. The man documentation is very bigcomplete but I didn't find any example on internet. What I initially wanted to do is to safely store a password entered by user inside a bash shell script and keep private to it (don't share with other processes).

Basically the script looks like :



keyctl new_session > /dev/null
keyid=`keyctl add user mail $password @s`
keyctl show
# echo "KEYID $keyid"
keyctl print $keyid

The first thing to do is to create a new session (to detach the current shared one).

Then we will add the password in the new item "mail". We don't have other choice to set type to "user". The item will be placed into the session keyring (@s). We could create new keyrings to store it with keyctl newring command. The command return item id as a big integer. We can use this integer or its name "%user:mail" for further references.

There is also a command keyctl padd which read data from stdin, but I don't recommend to use it as data is displayed in clear on the terminal.

Finally we show keyring information and print our password. We use print command to have an human friendly output, keyctl read command display it in hex format...

Friday, 27 July 2018
Écrit par
Grégory Soutadé

Today, a small Python script to track live stock exchanges. It fetch data from boursorama website and format it for "Generic Monitor" XFCE applet which allows to display result of a command line script. Just setup the path of this script in genmon properties and set the delay to 60s (to avoid flooding website).


# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <>.

import requests
import json

params_gettickseod = {"symbol":"%s","length":"1","period":"0","guid":""}
params_updatecharts = {"symbol":"%s","period":"-1"}

base_headers = {
    'Host': '',
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0',
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'fr,en-US;q=0.7,en;q=0.3',
    'DNT': '1',
    'Upgrade-Insecure-Requests': '1',
    'Pragma': 'no-cache',
    'Cache-Control': 'no-cache',
base_address = ''

headers = {
    'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Firefox/52.0',
    'Accept': 'application/json, text/javascript, */*; q=0.01',
    'Accept-Language': 'fr,en-US;q=0.7,en;q=0.3',
    'Accept-Encoding': 'gzip, deflate, br',
    'Referer': '',
    'Content-Type': 'application/json; charset=utf-8',
    'X-Requested-With': 'XMLHttpRequest',
    'DNT': '1',
    'Connection': 'keep-alive',

xhr_address = ''
address_gettickseod = xhr_address + 'GetTicksEOD'
address_updatecharts = xhr_address + 'UpdateCharts'

cookies = None

def _do_request(address, params, headers):
    if cookies is None:
        req = requests.get(address, params=params, headers=headers)
        req = requests.get(address, params=params, headers=headers, cookies=cookies)

    if req.status_code ==
        j = req.json()
        if len(j) == 0:
            raise Exception('Not available')
        return j
        raise Exception("Request error!")

def getStock(stock, display_name=None):
    my_headers = headers.copy()
    my_headers['Referer'] = headers['Referer'] % (stock)

    closevalue = 0
    res = ''

    my_params  = params_updatecharts.copy()
    my_params["symbol"] = stock
        j = _do_request(address_updatecharts, my_params, my_headers)
        req = requests.get(base_address + stock, headers=base_headers)
        # cookies = req.cookies
        j = _do_request(address_updatecharts, my_params, my_headers)

    current = float(j['d'][0]['c'])
    my_params  = params_gettickseod.copy()
    my_params["symbol"] = stock
        j = _do_request(address_gettickseod, my_params, my_headers)
        closevalue = float(j['d']['qv']['c'])
    except Exception, e:
        if not len(j):
            raise e
        closevalue = float(j['d'][0]['o']) # Open value

    if closevalue != 0:
        var = ((current/closevalue) - 1)*100
        var = 0
    if current < closevalue:
        color = 'red'
        var = -var
        color = 'green'
    if not display_name is None:
        res += '%s ' % (display_name)
    res += '%.3f <span fgcolor="%s">%.2f</span>' % (current, color, var)

    return res

def getMail():
    res = ''
    nb_messages = ''
    pipew = open("/tmp/gmail-pipe-w", "wb+")
    piper = open("/tmp/gmail-pipe-r", "rb+")
    while not len(nb_messages):
        nb_messages = piper.readline()
    if len(nb_messages):
        nb_messages = int(nb_messages)
        if nb_messages == 1:
            res = ', 1 msg'
        elif nb_messages > 1:
            res = ', %d msgs' % (nb_messages)

    return res

def getStocks(stocks):
    res = ''
    for stock in stocks:
        if res != '': res += ', '
            res += getStock(*stock)
        except Exception, e:
            if len(stock) > 1:
                res += "%s %s" % (stock[1], str(e))
                res += str(e)
    res += getMail()
    print('<txt>%s</txt>' % (res))

getStocks([('1rPENX', 'Euronext'), ('1rPAIR',)])

Get stock code id from website URL (last part). A file version is available here.

I added another part to get email count from gmail. It relies on a bash script that fetches RSS feeds when data is wrote in the FIFO.

Body of the script :



while [ 1 ] ; do
    echo -n "Please enter gmail account password : "
    read -s password
    echo ""
    echo -n "Confirm password : "
    read -s password2
    echo ""
    if [ "$password" != "$password2" ] ; then
        echo -e "Passwords doesn't match !!\n"


rm -f $pipew $piper
mkfifo $pipew $piper

while [ 1 ] ; do
    read line < $pipew
    feeds=`curl -u "$USER:$password" --silent ""`
    echo $feeds | sed  s/.*\<fullcount\>//g | sed  s/\<\\/fullcount\>.*//g > $piper

You can hardcode password in the script, but I don't like having my password in clear on the harddrive. A file version is available here.

Monday, 02 July 2018
Écrit par
Grégory Soutadé

Logo gPass

Mise à jour en catastrophe de gPass. Le dernier commit ayant introduit un bug dans la génération des wildcards. Oui, je sais, ça fait déjà 6 mois... Les extensions sont normalement mises à jour automatiquement, donc il n'y a rien à faire (aucun changement n'est à signaler côté serveur).

Pour se tenir informé : Mailing list gPass

Monday, 14 May 2018
Écrit par
Grégory Soutadé

Fenêtre principale de KissCount

Enfin ! Après avoir retravaillé l'empaquetement, la compilation et la documentation, voici la version 0.7 de KissCount ! Cela fait un an et demi depuis la dernière version (qui ne comportait que peu de correctifs). En réalité, cette mouture était prête depuis 6 mois, mais j'étais occupé à mettre en place Pannous.

Et pour une version, c'est une belle version, avec en figure de proue la migration vers Qt5 (qui a principalement motivé son développement), ainsi qu'un nouvel exécutable pour Windows ! Là aussi, il y avait un gros retard, puisque le dernier binaire en date était la 0.4 de ... 2013. Cette fois-ci, elle est compilée nativement depuis Visual Studio/Windows 10, alors qu'auparavant, j'utilisais mingw en cross compilation depuis Linux.

À ma grande surprise, la migration de Qt4 vers Qt5 s'est faite tout en douceur avec très peu de changements nécessaires. Cela a surtout été l'occasion de se débarrasser de libkdcharts au profit de la bibliothèque de dessin intégrée à Qt (même si je ne suis pas pleinement satisfait du rendu des graphiques circulaires). Le panneau principal a subi une légère modification, puisque le calendrier migre en bas à gauche, ce qui permet de gagner de la place et d'être plus cohérent.

Autre fonctionnalité intéressante : lorsqu'un compte descend en dessous d'une certaine limite (200€ par défaut) ou en dessous de 0, les jours du calendrier sont colorés (en jaune (configurable) et rouge). Également, plutôt que de "cacher" les comptes clôturés, j'ai intégré une date de début et de fin, plus pratique (je sais, c'est une fonctionnalité de base chez la concurrence...). Finalement, tout un tas de petits bugs ont été corrigés.

Bref, une bien belle version pour inaugurer la nouvelle liste de diffusion