Latest posts for tag truelite
Free as in Facebook
Yesterday we were in an airport. We tried to connect to the airport "free" wifi. It had a captive portal that asked for a lot of personal information before one could maybe get on the internet, and we gave up. Bologna Airport, no matter what they do to pretend that they like you, it's always clear that they don't.
I looked at the captive portal screen and I said: «ah yes, "free" wifi. Free as in Facebook».
We figured that we had an expression that will want to be reused.
Setting up Akonadi
Now that I have a CalDAV server that syncs with my phone I would like to use it from my desktop.
It looks like akonadi is able to sync with CalDAV servers, so I'm giving it a try.
First thing first is to give a meaning to the arbitrary name of this thing. Wikipedia says it is the oracle goddess of justice in Ghana. That still does not hint at all at personal information servers, but seems quite nice. Ok. I gave up with software having purpose-related names ages ago.
# apt-get install akonadi-server akonadi-backend-postgresql
Akonadi wants a SQL database as a backend. By default it uses MySQL, but I had enough of MySQL ages ago.
I tried SQLite but the performance with it is terrible. Terrible as in, it takes 2 minutes between adding a calendar entry and having it show up in the calendar. I'm fascinated by how Akonadi manages to use SQLite so badly, but since I currently just want to get a job done, next in line is PostgreSQL:
# su - postgres
$ createuser enrico
$ psql postgres
postgres=# alter user enrico createdb;
Then as enrico
:
$ createdb akonadi-enrico
$ cat <<EOT > ~/.config/akonadi/akonadiserverrc
[%General]
Driver=QPSQL
[QPSQL]
Name=akonadi-enrico
StartServer=false
Host=
Options=
ServerPath=
InitDbPath=
I can now use kontact to connect Akonadi to my CalDAV server and it works nicely, both with calendar and with addressbook entries.
KDE has at least two clients for Akonadi: Kontact, which is a kitchen sink application similar to Evolution, and KOrganizer, which is just the calendar and scheduling component of Kontact.
Both work decently, and KOrganizer has a pretty decent startup time. I now have a usable desktop PIM application that is synced with my phone. W00T!
Next step is to port my swift little calendar display tool to use Akonadi as a back-end.
seat-inspect
Four months ago I wrote this somewhere:
Seeing a DD saying "this new dbus stuff scares me" would make most debian users scared. Seeing a DD who has an idea of what is going on, and who can explain it, would be an interesting and exciting experience.
So, let's be exemplary, competent and patient. Or at least, competent. Some may like or not like the changes, but do we all understand what is going on? Will we all be able to support our friends and customers running jessie?
I confess that although I understand the need for it, I don't feel competent enough to support systemd-based machines right now.
So, are we maybe in need of help, cheat sheets, arsenals of one-liners, diagnostic tools?
Maybe a round of posts on -planet like "one debian package a day" but with new features that jessie will have, and how to understand them and take advantage of them?
That was four months ago. In the meantime, I did some work, and it got better for me.
Yesterday, however, I've seen an experienced Linux person frustrated because the shutdown function of the desktop was doing nothing whatsoever. Today I found John Goerzen's post on planet.
I felt like some more diagnostic tools were needed, so I spent the day making seat-inspect.
seat-inspect tries to make the status of the login/seat system visible, to help with understanding and troubleshooting.
The intent of running the code is to have an overview of the system status, both to see what the new facilities are about, and to figure out if there is something out of place.
The intent of reading the code is to have an idea of how to use these facilities: the code has been written to be straightforward and is annotated with relevant bits from the logind API documentation.
seat-inspect is not a finished tool, but a starting point. I put it on github hoping that people will fork it and add their own extra sanity checks and warnings, so that it can grow into a standard thing to run if a system acts weird.
As it is now, it should be able to issue warnings if some bits are missing for network-manager or shutdown functions to work correctly. I haven't really tested that, though, because I don't have a system at hand where they are currently not working fine.
Another nice thing of it is that when running seat-inspect -v
you get a dump
of what logind/consolekit think about your system. I found it an interesting
way to explore the new functionalities that we recently grew. The same can be
done, and in more details, with loginctl
calls, but I lacked a summary.
After writing this I feel a bit more competent, probably enough to sit at somebody's computer and poke into loginctl bits. I highly recommend the experience.
Playing with python, terminfo and command output
I am experimenting with showing progress on the terminal for a subcommand that is being run, showing what is happening without scrolling away the output of the main program, and I came out with this little toy. It shows the last X lines of a subcommand output, then gets rid of everything after the command has ended.
Usability-wise, it feels like a tease to me: it looks like I'm being shown all sorts of information then they are taken away from me before I managed to make sense of them. However, I find it cute enough to share:
#!/usr/bin/env python3
#coding: utf-8
# Copyright 2015 Enrico Zini <enrico@enricozini.org>. Licensed under the terms
# of the GNU General Public License, version 2 or any later version.
import argparse
import fcntl
import select
import curses
import contextlib
import subprocess
import os
import sys
import collections
import shlex
import shutil
import logging
def stream_output(proc):
"""
Take a subprocess.Popen object and generate its output, line by line,
annotated with "stdout" or "stderr". At process termination it generates
one last element: ("result", return_code) with the return code of the
process.
"""
fds = [proc.stdout, proc.stderr]
bufs = [b"", b""]
types = ["stdout", "stderr"]
# Set both pipes as non-blocking
for fd in fds:
fcntl.fcntl(fd, fcntl.F_SETFL, os.O_NONBLOCK)
# Multiplex stdout and stderr with different prefixes
while len(fds) > 0:
s = select.select(fds, (), ())
for fd in s[0]:
idx = fds.index(fd)
buf = fd.read()
if len(buf) == 0:
fds.pop(idx)
if len(bufs[idx]) != 0:
yield types[idx], bufs.pop(idx)
types.pop(idx)
else:
bufs[idx] += buf
lines = bufs[idx].split(b"\n")
bufs[idx] = lines.pop()
for l in lines:
yield types[idx], l
res = proc.wait()
yield "result", res
@contextlib.contextmanager
def miniscreen(has_fancyterm, name, maxlines=3, silent=False):
"""
Show the output of a process scrolling in a portion of the screen.
has_fancyterm: true if the terminal supports fancy features; if false, just
write lines to standard output
name: name of the process being run, to use as a header
maxlines: maximum height of the miniscreen
silent: do nothing whatsoever, used to disable this without needing to
change the code structure
Usage:
with miniscreen(True, "my process", 5) as print_line:
for i in range(10):
print_line(("stdout", "stderr")[i % 2], "Line #{}".format(i))
"""
if not silent and has_fancyterm:
# Discover all the terminal control sequences that we need
output_normal = str(curses.tigetstr("sgr0"), "ascii")
output_up = str(curses.tigetstr("cuu1"), "ascii")
output_clreol = str(curses.tigetstr("el"), "ascii")
cols, lines = shutil.get_terminal_size()
output_width = cols
fg_color = (curses.tigetstr("setaf") or
curses.tigetstr("setf") or "")
sys.stdout.write(str(curses.tparm(fg_color, 6), "ascii"))
output_lines = collections.deque(maxlen=maxlines)
def print_lines():
"""
Print the lines in our buffer, then move back to the beginning
"""
sys.stdout.write("{} progress:".format(name))
sys.stdout.write(output_clreol)
for msg in output_lines:
sys.stdout.write("\n")
sys.stdout.write(msg)
sys.stdout.write(output_clreol)
sys.stdout.write(output_up * len(output_lines))
sys.stdout.write("\r")
try:
print_lines()
def _progress_line(type, line):
"""
Print a new line to the miniscreen
"""
# Add the new line to our output buffer
msg = "{} {}".format("." if type == "stdout" else "!", line)
if len(msg) > output_width - 4:
msg = msg[:output_width - 4] + "..."
output_lines.append(msg)
# Update the miniscreen
print_lines()
yield _progress_line
# Clear the miniscreen by filling our ring buffer with empty lines
# then printing them out
for i in range(maxlines):
output_lines.append("")
print_lines()
finally:
sys.stdout.write(output_normal)
elif not silent:
def _progress_line(type, line):
print("{}: {}".format(type, line))
yield _progress_line
else:
def _progress_line(type, line):
pass
yield _progress_line
def run_command_fancy(name, cmd, env=None, logfd=None, fancy=True, debug=False):
quoted_cmd = " ".join(shlex.quote(x) for x in cmd)
log.info("%s running command %s", name, quoted_cmd)
if logfd: print("runcmd:", quoted_cmd, file=logfd)
# Run the script itself on an empty environment, so that what was
# documented is exactly what was run
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env)
with miniscreen(fancy, name, silent=debug) as progress:
stderr = []
for type, val in stream_output(proc):
if type == "stdout":
val = val.decode("utf-8")
if logfd: print("stdout:", val, file=logfd)
log.debug("%s stdout: %s", name, val)
progress(type, val)
elif type == "stderr":
val = val.decode("utf-8")
if logfd: print("stderr:", val, file=logfd)
stderr.append(val)
log.debug("%s stderr: %s", name, val)
progress(type, val)
elif type == "result":
if logfd: print("retval:", val, file=logfd)
log.debug("%s retval: %d", name, val)
retval = val
if retval != 0:
lastlines = min(len(stderr), 5)
log.error("%s exited with code %s", name, retval)
log.error("Last %d lines of standard error:", lastlines)
for line in stderr[-lastlines:]:
log.error("%s: %s", name, line)
return retval
parser = argparse.ArgumentParser(description="run a command showing only a portion of its output")
parser.add_argument("--logfile", action="store", help="specify a file where the full execution log will be written")
parser.add_argument("--debug", action="store_true", help="debugging output on the terminal")
parser.add_argument("--verbose", action="store_true", help="verbose output on the terminal")
parser.add_argument("command", nargs="*", help="command to run")
args = parser.parse_args()
if args.debug:
loglevel = logging.DEBUG
elif args.verbose:
loglevel = logging.INFO
else:
loglevel = logging.WARN
logging.basicConfig(level=loglevel, stream=sys.stderr)
log = logging.getLogger()
fancy = False
if not args.debug and sys.stdout.isatty():
curses.setupterm()
if curses.tigetnum("colors") > 0:
fancy = True
if args.logfile:
logfd = open("output.log", "wt")
else:
logfd = None
retval = run_command_fancy("miniscreen example", args.command, logfd=logfd)
sys.exit(retval)
Upgrade Cyanogenmod with an encrypted phone
Cyanogenmod found an update, it downloaded it, then it rebooted to install it and nothing happened. It turns out that the update procedure cannot work if the zip file to install is in encrypted media, so a workaround is to move the zip into unencrypted external storage.
As far as I know, my Nexus 4 has no unencrypted external storage.
This is how I managed to upgrade it, I write it here so I can find it next time:
- enable USB debugging
adb pull /cmupdater/cm-11-20141115-SNAPSHOT-M12-mako.zip
adb reboot recovery
- choose "install zip from sideload"
adb sideload cm-11-20141115-SNAPSHOT-M12-mako.zip
Radicale and DAVDroid
radicale and DAVdroid appeal to me. Let's try to make the whole thing work.
A self-signed SSL certificate
Update: use this method
instead, to avoid apache complaining that server certificate is a CA
certificate
.
Generating the certificate:
openssl req -nodes -x509 -newkey rsa:2048 -keyout cal-key.pem -out cal-cert.pem -days 3650
[...]
Country Name (2 letter code) [AU]:IT
State or Province Name (full name) [Some-State]:Bologna
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:enricozini.org
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:cal.enricozini.org
Email Address []:postmaster@enricozini.org
Installing it on my phone:
openssl x509 -in cal-cert.pem -outform DER -out cal-cert.crt
adb push cal-cert.crt /mnt/sdcard/
enrico --follow-instructions http://davdroid.bitfire.at/faq/entry/importing-a-certificate
Installing radicale in my VPS
Update: there is already a new version of radicale available in Debian testing.
An updated radicale package, with this patch to make it work with DAVDroid:
apt-get source radicale
# I reviewed 063f7de7a2c7c50de5fe3f8382358f9a1124fbb6
git clone https://github.com/Kozea/Radicale.git
Move the python code from git to the Debian source
dch -v 0.10~enrico-1 "Pulled in the not yet released 0.10 work from upstream"
debuild -us -uc -rfakeroot
Install the package:
# dpkg -i python-radicale_0.10~enrico0-1_all.deb
# dpkg -i radicale_0.10~enrico0-1_all.deb
Create a system user to run it:
# adduser --system --disabled-password radicale
Configure it (/etc/radicale/config
) for mod_wsgi
with auth done by Apache:
# For brevity, this is my config file with comments removed
[storage]
# Storage backend
# Value: filesystem | multifilesystem | database | custom
type = filesystem
# Folder for storing local collections, created if not present
filesystem_folder = /var/lib/radicale/collections
[logging]
config = /etc/radicale/logging
Create the wsgi file to run it:
# mkdir /srv/radicale
# cat <<EOT > /srv/radicale/radicale.wsgi
import radicale
radicale.log.start()
application = radicale.Application()
EOT
# chown radicale.radicale /srv/radicale/radicale.wsgi
# chmod 0755 /srv/radicale/radicale.wsgi
Make radicale commit to git
# apt-get install python-dulwich
# cd /var/lib/radicale/collections
# git init
# chown radicale.radicale -R /var/lib/radicale/collections/.git
Apache configuration
Add a new site to apache:
$ cat /etc/apache2/sites-available/cal.conf
# For brevity, this is my config file with comments removed
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName cal.enricozini.org
ServerAdmin enrico@enricozini.org
Alias /robots.txt /srv/radicale/robots.txt
Alias /favicon.ico /srv/radicale/favicon.ico
WSGIDaemonProcess radicale user=radicale group=radicale threads=1 umask=0027 display-name=%{GROUP}
WSGIProcessGroup radicale
WSGIScriptAlias / /srv/radicale/radicale.wsgi
<Directory /srv/radicale>
# WSGIProcessGroup radicale
# WSGIApplicationGroup radicale
# WSGIPassAuthorization On
AllowOverride None
Require all granted
</Directory>
<Location />
AuthType basic
AuthName "Enrico's Calendar"
AuthBasicProvider file
AuthUserFile /usr/local/etc/radicale/htpasswd
Require user enrico
</Location>
ErrorLog{APACHE_LOG_DIR}/cal-enricozini-org-error.log
LogLevel warn
CustomLog{APACHE_LOG_DIR}/cal-enricozini-org-access.log combined
SSLEngine on
SSLCertificateFile /etc/ssl/certs/cal.pem
SSLCertificateKeyFile /etc/ssl/private/cal.key
</VirtualHost>
</IfModule>
Then enable it:
# a2ensite cal.conf
# service apache2 reload
Create collections
DAVdroid seems to want to see existing collections on the server, so we create them:
$ apt-get install cadaver
$ cat <<EOT > /tmp/empty.ics
BEGIN:VCALENDAR
VERSION:2.0
END:VCALENDAR
EOT
$ cat <<EOT > /tmp/empty.vcf
BEGIN:VCARD
VERSION:2.1
END:VCARD
EOT
$ cadaver https://cal.enricozini.org
WARNING: Untrusted server certificate presented for `cal.enricozini.org':
[...]
Do you wish to accept the certificate? (y/n) y
Authentication required for Enrico's Calendar on server `cal.enricozini.org':
Username: enrico
Password: ****
dav:/> cd enrico/contacts.vcf/
dav:/> put /tmp/empty.vcf
dav:/> cd ../calendar.ics/
dav:/> put /tmp/empty.ics
dav:/enrico/calendar.ics/> ^D
Connection to `cal.enricozini.org' closed.
DAVdroid configuration
- Add a new DAVdroid sync account
- Use server/username configuration
- For server, use https://
/ / - Add username and password
It should work.
Related links
Alternate rescue boot entry with systemd
Since systemd version 215, adding systemd.debug-shell
to the kernel command
line activates the debug shell on tty9 alongside the normal boot. I like the
idea of that, and I'd like to have it in my standard 'rescue' entry in my grub
menu.
Unfortunately, by default update-grub
does not allow to customize the rescue
menu entry options. I have just filed #766530
hoping for that to change.
After testing the patch I proposed for /etc/grub.d/10_linux
, I now have this
in my /etc/default/grub
, with some satisfaction:
GRUB_CMDLINE_LINUX_RECOVERY="systemd.log_target=kmsg systemd.log_level=debug systemd.debug-shell"
Further information:
Thanks to sjoerd and uau on #debian-systemd for their help.
Spelling a chilometri zero
Lo spelling internazionale è troppo globalizzato, e volete recuperare un attimo la dimensione del posto dove siete nati e cresciuti?
Da oggi c'è questo script che fa per voi: gli dite dove abitate, e lui vi crea lo spelling a chilometri zero.
$ git clone git@gitorious.org:trespolo/osmspell.git
$ cd osmspell
$ ./osmspell "San Giorgio di Piano"
1: San Giorgio di Piano, BO, EMR, Italia
2: San Giorgio di Piano, Via Codronchi, San Giorgio di Piano, BO, EMR, Italia
3: San Giorgio Di Piano, Via Libertà, San Giorgio di Piano, BO, EMR, Italia
Choose one: 1
Center: 44.6465332, 11.3790398
A Argelato, Altedo
B Bentivoglio, Bologna, Boschi
C Cinquanta, Castagnolo Minore, Castel Maggiore, Cento
D Dosso
E Eremo di Tizzano
F Funo di Argelato, Finale Emilia, Ferrara, Fiesso
G Gherghenzano, Galliera, Gesso
I Il Cucco, Irnerio, Idice
L Località Fortuna, Lovoleto, Lippo
M Malacappa, Massumatico, Minerbio, Marano
N Navile
O Osteriola, Ozzano dell'Emilia, Oca
P Piombino, Padulle, Poggio Renatico, Piave
Q Quarto Inferiore, Quattrina
R Rubizzano, Renazzo, Riale
S San Giorgio di Piano, Saletto
T Torre Verde, Tintoria, Tombe
U Uccellino
V Venezzano Mascarino, Vigarano Mainarda, Veduro
X XII Morelli
Z Zenerigolo, Zola Predosa
I dati vengono da OSM, e lo script è un ottimo esempio di come usarne la API di geolocazione (veloci) e la API di query geografica (lenta).
Update: source code is now here.