1
0
Fork 0

initial commit

This commit is contained in:
Harald Hoyer 2020-05-19 18:20:18 +02:00
commit 429a176559
59 changed files with 4097 additions and 0 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
/public
/.idea/
/blog.iml

56
config.toml Normal file
View file

@ -0,0 +1,56 @@
title = "Harald Hoyer"
description = "Triple Faults for Debug"
# The URL the site will be built for
base_url = "https://harald.hoyer.xyz"
# Whether to automatically compile all Sass files in the sass directory
compile_sass = true
# Whether to do syntax highlighting
# Theme can be customised by setting the `highlight_theme` variable to a theme supported by Zola
highlight_code = true
# Whether to build a search index to be used later on by a JavaScript library
build_search_index = true
theme = "zola-clean-blog"
taxonomies = [
{name = "categories", rss = true, paginate_by=5},
{name = "tags", rss = true, paginate_by=5},
]
generate_rss = true
#highlight_theme = "dracula"
#highlight_theme = "inspired-github"
highlight_theme = "ir-white"
#highlight_theme = "material-light"
extra_syntaxes = [
"syntaxes",
"syntaxes/Sublime-varlink",
"syntaxes/Sublime-console",
]
[extra]
# Put all your custom variables here
author = "Harald Hoyer"
clean_blog_menu = [
{url = "$BASE_URL", name = "Home"},
{url = "https://photo-harald.hoyer.xyz/", name = "Photos"},
{url = "$BASE_URL/impressum", name = "Impressum"},
]
clean_blog_social = [
{url = "https://hoyer.xyz/profile/harald", icon="fab fa-mastodon"},
{url = "https://github.com/haraldh", icon="fab fa-github"},
{url = "https://keybase.io/haraldhoyer/", icon="fab fa-keybase"},
{url = "https://twitter.com/haraldhoyer", icon="fab fa-twitter"},
{url = "$BASE_URL/rss.xml", icon="fas fa-rss"}
]

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,18 @@
+++
title = "dracut - kernel command line"
date = 2013-11-04T18:36:27+00:00
+++
To quickly find out, what dracut wants as the kernel command for your current disk setup,
fire up:
```console
# dracut --print-cmdline
```
<!-- more -->
It will output something like:
```bash
root=UUID=8b8b6f91-95c7-4da2-831b-171e12179081
rootflags=rw,relatime,discard,data=ordered
rootfstype=ext4
```
This works for version 032 and newer.

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,17 @@
+++
title = "Redirecting apache access_log and error_log to the systemd journal"
date = 2013-11-07T10:03:38+00:00
+++
To redirect all apache messages to syslog, which will then appear in the systemd
journal modify your httpd.conf:
<!-- more -->
```properties
CustomLog "|/bin/logger -t access_log -p user.info" "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\""``
ErrorLog syslog:user
```
Of course it would be much nicer, if apache actually could use the journal directly.
\[Edit\]: Apparently with apache 2.5, there will be a [mod\_journald](http://httpd.apache.org/docs/trunk/mod/mod_journald.html) :\-)

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,152 @@
+++
title = "Fedora Boot Optimization"
date = 2013-11-13T10:12:04+00:00
+++
This article shows how to reduce boot time for Fedora 17, but the recipe can also be applied to 18, 19 and 20.
The target is to get a fast booting system with NetworkManager running and gdm displaying the login
screen as fast as possible.
<!-- more -->
The system I use here is a Lenovo T420s (2x2x Intel(R) Core(TM) i5-2540M CPU @ 2.60GHz)
with an INTEL SSDSA2BW160G3L harddrive.
First we choose a manual disk layout and use primary partitions and format them with ext4.
In my case this results in:
```sda1 ext4 /boot
sda2 swap
sda3 ext4
```
After the first boot, setup of the user, etc. and 2 reboots (always reboot 2 times,
before taking the measurement, because readahead needs to adapt to the changed boot process).
First we update everything.
```console
$ sudo yum update
```
After the reboots, I get:
```console
$ systemd-analyze
Startup finished in 1413ms (kernel) + 2911ms (initramfs) + 10593ms (userspace) = 14918ms
```
Because I don't use any LVM, RAID or encrypted devices, I can safely turn off all nearly all
`fedora-\*storage\*` services. To turn off these services, we use the `systemctl mask` command.
A bonus with that mechanism is, that no rpm %post script turns them on automatically.
```console
$ cd /lib/systemd/system
$ for i in fedora*storage* lvm2-monitor.* mdmonitor*.*; \
do sudo systemctl mask $i; \
done
```
On Fedora 17, it seems there are still some SysV initscripts left, so we turn them off:
```console
$ for i in livesys livesys-late spice-vdagentd;\
do sudo chkconfig $i off;\
done
```
Seems like we saved half of the time in userspace:
```console
$ systemd-analyze
Startup finished in 1640ms (kernel) + 6556ms (userspace) = 8197ms
```
From now on, you really have to know what you are doing and how to revert your actions.
To compare Fedora with e.g. Ubuntu, I will now turn off all services except NetworkManager.
The result will be a Linux system without mail, firewall, printing, the abrt tools, avahi,
some mountpoints, rsyslog, irqbalance, and selinux security.
```console
$ cd /lib/systemd/system
$ for i in abrt*.service auditd.service avahi-daemon.* \
bluetooth.* dev-hugepages.mount dev-mqueue.mount \
fedora-configure.service fedora-loadmodules.service \
fedora-readonly.service ip6tables.service \
iptables.service irqbalance.service mcelog.service \
rsyslog.service sendmail.service sm-client.service \
sys-kernel-config.mount sys-kernel-debug.mount; do \
sudo systemctl mask "$i"; \
done
```
To disable selinux (only for measurements!), edit `/etc/selinux/config` and add `selinux=0`
to the kernel command line.
My `/etc/grub2.cfg` now looks like this:
```
linux /vmlinuz-3.3.7-1.fc17.x86_64 root=/dev/sda3 rootfstype=ext4 libahci.ignore_sss=1 raid=noautodetect selinux=0
initrd /initramfs-3.3.7-1.fc17.x86_64.img
```
Now we are really fast!
```console
$ systemd-analyze
Startup finished in 1329ms (kernel) + 1596ms (userspace) = 2926ms
```
I also like the idea of automounting (systemd's automount feature was an idea of mine :-).
So I turn /boot in a "mount on demand" mountpoint. Also having /tmp as a tmpfs is one way to reduce
disk activity (useful for e.g. a slow flash disk). My resulting /etc/fstab looks like this:
```
/dev/sda3 / ext4 defaults 1 1
/dev/sda1 /boot ext4 noauto,comment=systemd.automount 1 2
/dev/sda2 swap swap defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
```
This only saved a little bit of time, but still:
```console
$ systemd-analyze
Startup finished in 1342ms (kernel) + 1426ms (userspace) = 2769ms
```
Because NetworkManager is started also by the graphical login target,
I can remove it from the multi-user target and it will be started in parallel to the gdm login screen.
```console
$ sudo rm /etc/systemd/system/multi-user.target.wants/NetworkManager.service
```
This will shave of a few milliseconds:
```console
$ systemd-analyze
Startup finished in 1323ms (kernel) + 1279ms (userspace) = 2603ms
```
To see the difference readahead makes for the system, I turn it off temporarily and reboot
```console
$ cd /lib/systemd/system
$ for i in *readahead*; do sudo systemctl mask $i;done
```
Which will give us:
```console
$ systemd-analyze
Startup finished in 1336ms (kernel) + 1210ms (userspace) = 2547ms
```
This time is a little bit misleading. Although it seems faster, the real time until the login screen
is displayed is taking longer. So a fair comparison would involve a **stopwatch**.
To turn off plymouth, because we want speed and not eye candy, I remove plymouth completely
and regenerate the initramfs to get rid of it.
```console
$ sudo yum remove 'plymouth*'
$ sudo dracut -f
```
After a reboot we get the stunning result of:
```console
$ systemd-analyze
Startup finished in 612ms (kernel) + 499ms (initramfs) + 1330ms (userspace) = 2443ms
```
The nice thing about `systemctl mask` is, that you can always unmask it via `systemctl unmask`
and only enable those default services, which you really need.
Now, **turn selinux back on**, edit `/etc/selinux/config` and remove `selinux=0` from the kernel command line.
You really don't want to trade some seconds for security!
Have fun and happy rebooting!
And don't forget to reboot twice to let the readahead optimization kick in!

View file

@ -0,0 +1,17 @@
+++
title = "Linux: HOWTO get the number of CPUs"
date = 2013-11-13T12:13:04+00:00
+++
```console
$ getconf _NPROCESSORS_ONLN
```
returns the number of CPUs online.
<!-- more -->
Internally it is parsing
`/sys/devices/system/cpu/online`, which can have the contents: `0-3,5,7-9`.
Better let getconf [do all the counting for you](https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/getsysstats.c#l127).
This is very useful, if you want to optimize the number of threads.

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

5
content/2013/_index.md Normal file
View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,71 @@
+++
title = "Self Hosting Fedora Base"
date = 2014-01-14T16:15:52+00:00
+++
If you want to bootstrap a distribution or want to rebuild it from the sources (SRPMS) to get the same
binaries (think CentOS), you have to build the build tools and rebuild them with the built build tools,
which have to be built with other build tools…
My goal for a self-hosting Fedora Base is to reduce the number of packages to do such a rebuild.
<!-- more -->
The first step is to get the packages to build the most important component for a linux distribution - the kernel.
To get those packages, Phil Knirsch wrote a small python script, which calls `repoquery`.
I extended this script to output graphviz .dot formatted files.
The first run gives us [1806 packages](https://harald.fedorapeople.org/kernel-br-all.txt), with which you could build
the tools to build the tools to […] build the kernel, if you manage to break the dependency cycle, etc.
If you want to display this beast with e.g. "sfdp" and "gvmap" from the graphviz suite, this will give you a monster graph.
[<img alt="Self-Hosting kernel build requirements" src="https://harald.fedorapeople.org/kernel-br-all.png" height="333" width="800" />](https://harald.fedorapeople.org/kernel-br-all.svg)
Self-Hosting kernel build requirements
This was generated with the [kernel-br-all.dot](https://harald.fedorapeople.org/kernel-br-all.dot) file and the command:
```console
$ START=7; cat kernel-br-all.dot | \
sfdp -Gstart=$START -Goverlap=prism | \
gvmap -e -d $START | \
neato -Gstart=$START -n2 -Ecolor=#44444455 -Tsvg \
> kernel-br-all.svg
```
My next step was to identify the source of weird build requirements like `qt`, `kdelibs` or `wayland`.
So I build a list of packages, which might be removed from the build requirements, because they only build documentation
or willingly add a build requirement to a graphical component like X, wayland or a GUI.
After filtering those with [the python script](https://harald.fedorapeople.org/buildreq.py), the resulting graph was
mainly dominated by perl packages, so I just merged them in one "perl" node. The graph from this is almost readable.
[<img alt="Reduced Self-Hosting kernel build requirements" src="https://harald.fedorapeople.org/kernel-br-reduced.png" height="525" width="800" />](https://harald.fedorapeople.org/kernel-br-reduced.svg)
Reduced Self-Hosting kernel build requirements
`graphviz` comes with `tred`, which reduces the graph, so that at least one path leads from X to Y.
With this reduction we get a nice graph generated from
[kernel-br-reduced.dot](https://harald.fedorapeople.org/kernel-br-reduced.dot) by:
```console
$ START=7; tred kernel-br-reduced.dot | \
sfdp -Gstart=$START -Goverlap=prism | \
gvmap -e -d $START | \
neato -Gstart=$START -n2 -Ecolor=#44444455 -Tsvg \
> kernel-br-reduced-tred.svg
```
Now, most of the build requirements are missing, but one path, so you can at least find **one** package,
which requires a specific package. All the red nodes in the graph are the build requirements, for which no
build requirements were added. So the strategy should be to get rid of those, or make sure they don't pull in the #
complete distribution. We might want to use the pre-built documentation shipped with the package or have a separate
documentation build phase with the same source. For other packages, we might have to split out the GUI components.
If you have other ideas, I am happy to get to know them.
**Conclusion: 188 packages plus all the perl packages could form a basic buildroot to build itsself.
To achieve this, we have to take care of those 56 red packages, that these are not used.**
The list of the 65 spec files with the build requirements to ifdef can be found here:
[http://harald.fedorapeople.org/bootstrap-not-needed-deps.txt](https://harald.fedorapeople.org/bootstrap-not-needed-deps.txt)
[<img alt="" src="https://harald.fedorapeople.org/kernel-br-reduced-tred.svg" width="800" />](https://harald.fedorapeople.org/kernel-br-reduced-tred.svg)
Reduced Build Requirements for the package kernel

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

5
content/2014/_index.md Normal file
View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,41 @@
+++
title = "Single UEFI executable for kernel+initrd+cmdline"
date = 2015-02-25T15:55:16+00:00
+++
Lately Kay Sievers and David Herrmann created a UEFI
[loader stub](http://cgit.freedesktop.org/gummiboot/tree/src/efi/stub.c), which starts a linux kernel
with an initrd and a kernel command line, which are COFF sections of the executable.
This enables us to create single UEFI executable with a standard distribution kernel,
a custom initrd and our own kernel command line attached.
<!-- more -->
Of course booting a linux kernel
directly from the UEFI has been possible before with the kernel EFI stub. But to add an initrd and
kernel command line, this had to be specified at kernel compile time.
To demonstrate this feature
and have a useful product, I created a shell script, which creates a "rescue" image on Fedora with
the rescue kernel and rescue initrd. The kernel command line "rd.auto" instructs dracut to assemble
all devices, while waiting 20 seconds for device appearance "rd.retry=20" and drop to a final shell
because "root=/dev/failme" is specified (which does not exist of course). Now in this shell you can
fsck your devices, mount them and repair your system.
The shell script can be downloaded and viewed on
[github](https://github.com/haraldh/mkrescue-uefi).
To run the script, you will need to install gummiboot >= 46 and binutils.
```console
# yum install gummiboot binutils
```
Run the script:
```console
# bash mkrescue-uefi.sh BOOTX64.EFI
```
Copy `BOOTX64.EFI` to e.g. a USB stick to `EFI/BOOT/BOOTX64.EFI` in the FAT boot partition
and point your BIOS to boot from the USB stick. Voilà!
A rescue USB stick with just one file! :-)

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,79 @@
+++
title = "libtool: getting rid of 180,000 sed forks"
date = 2015-03-05T08:10:36+00:00
+++
When compiling systemd on rawhide, we noticed a significant slowdown in compile time.
Investigating further, it turns out, that libtool forks an incredible amount of sed.
Running perf showed 30% of the "make all" was spent in bash. strace showed an execve of
sed with the same arguments 180,000 times!!!!!
<!-- more -->
Looking in the code reveals the culprit:
```bash
_G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;;
```
and
```bash
qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
```
`sed_quote_subst` looks like this:
```bash
sed_quote_subst='s|\([`"$\\]\)|\\\1|g'
```
This substitution can be easily done in bash, without forking sed. So I came up with a patch for libtool:
```diff
--- libtool.orig 2015-03-04 15:44:39.632703654 +0100
+++ libtool.fixed 2015-03-04 17:16:42.495983610 +0100
@@ -1607,7 +1607,15 @@
while test 0 -lt $#; do
case $1 in
*[\\\`\"\$]*)
- _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;;
+ if test set = "${BASH_VERSION+set}"; then
+ _G_unquoted_arg=${1//\\/\\\\}
+ _G_unquoted_arg=${_G_unquoted_arg//\"/\\\"}
+ _G_unquoted_arg=${_G_unquoted_arg//\$/\\\$}
+ _G_unquoted_arg=${_G_unquoted_arg//\`/\\\`}
+ else
+ _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"`
+ fi
+ ;;
*)
_G_unquoted_arg=$1 ;;
esac
@@ -5756,7 +5764,11 @@
if test \"\$libtool_execute_magic\" != \"$magic\"; then
file=\"\$0\""
- qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+ if test set = "${BASH_VERSION+set}"; then
+ qECHO=$(_G=$($ECHO "$ECHO");_G=${_G//\\/\\\\};_G=${_G//\"/\\\"};_G=${_G//\$/\\\$};_G=${_G//\`/\\\`};printf '%s\n' "$_G")
+ else
+ qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+ fi
$ECHO "\
```
With that patch, I compared the runtime of a compile (with ccache on). Original libtool:
```console
$ time make -j4
[…]
real 5m23.880s
user 11m39.731s
sys 7m12.578s
```
Fixed libtool:
```console
$ time make -j4
[…]
real 2m47.325s
user 9m33.561s
sys 0m57.522s
```
The old version spent half of the time creating a pipe, forking sed and parsing the
output. Someone with connections to the libtool maintainers, please point them to
this problem! Reported as [bug 20006](http://debbugs.gnu.org/cgi/bugreport.cgi?bug=20006).

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,357 @@
+++
title = "A Python Transaction Class"
date = 2015-10-13T10:20:43+00:00
+++
This is a repost of a blog post of 2008. Just for the reference :-)
This class allows sub-classes to commit changes to an instance to a history, and rollback to previous states.
<!-- more -->
The final class with an extension for `__setstate__` and `__getstate__` can be found here:
[transaction.py](/files/transaction.py)
and [transaction_test.py](/files/transaction_test.py).
Now to the story, that led to it: I had the need for a transaction class in python and browsing the python cookbook led me to a [small Transaction class](http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/551788).
```python
$ python
Python 2.5.1 (r251:54863, Oct 30 2007, 13:45:26)
[GCC 4.1.2 20070925 (Red Hat 4.1.2-33)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> class Transaction(object):
... def __init__(self):
... self.log = []
... def commit(self):
... self.log.append(self.__dict__.copy())
... def rollback(self):
... try:
... self.__dict__.update(self.log.pop(-1))
... except IndexError:
... pass
...
```
Ok, lets have some fun with it.
```python
>>> class A(Transaction):
... pass
...
>>> a = A()
>>> a.test = True
>>> a.commit()
>>> a.test = False
>>> a
'self.__dict__ = {'test': False, 'log': [{'test': True, 'log': [...]}]}'
>>> a.rollback()
>>> a
'self.__dict__ = {'test': True, 'log': []}'
```
Nice. Let's see if we can commit and rollback several times.
```python
>>> a = A()
>>> a.test = 1
>>> a.commit()
>>> a.test = 2
>>> a.commit()
>>> a.test = 3
>>> a
'self.__dict__ = {'test': 3, 'log': [{'test': 1, 'log': [...]}, {'test': 2, 'log': [...]}]}'
>>> a.rollback()
>>> a
'self.__dict__ = {'test': 2, 'log': [{'test': 1, 'log': [...]}]}'
>>> a.rollback()
>>> a
'self.__dict__ = {'test': 1, 'log': []}'
```
Ok.. works :) Let's try some lists.
```python
>>> a = A()
>>> a.test = [ 0, 1 ]
>>> a.commit()
>>> a.test.append(2)
>>> a
'self.__dict__ = {'test': [0, 1, 2], 'log': [{'test': [0, 1, 2], 'log': [...]}]}'
>>> a.rollback()
>>> a
'self.__dict__ = {'test': [0, 1, 2], 'log': []}'
```
Doh! Ok, someone mentioned that already in the comments. copy.deepcopy() is the key.
```python
>>> import copy
>>>
>>> class Transaction2(Transaction):
... def commit(self, **kwargs):
... self.log.append(copy.deepcopy(self.__dict__))
...
>>> class A(Transaction2):
... pass
...
>>> a = A()
>>> a.test = [ 0, 1 ]
>>> a.commit()
>>> a.test.append(2)
>>> a
'self.__dict__ = {'test': [0, 1, 2], 'log': [{'test': [0, 1], 'log': []}]}'
>>> a.rollback()
>>> a
'self.__dict__ = {'test': [0, 1], 'log': []}'
```
Ah, works. Very good. Now another check:
```python
>>> a = A()
>>> a.test = 1
>>> a.commit()
>>> a
'self.__dict__ = {'test': 1, 'log': [{'test': 1, 'log': []}]}'
>>> a.other = 2
>>> a
'self.__dict__ = {'test': 1, 'other': 2, 'log': [{'test': 1, 'log': []}]}'
>>> a.rollback()
>>> a
'self.__dict__ = {'test': 1, 'other': 2, 'log': []}'
>>> a.other
2
```
Oh, a leftover... seems like `self.__dict__` has to be cleared, before the update.
```python
>>> class Transaction3(Transaction2):
... def rollback(self, **kwargs):
... try:
... state = self.log.pop(-1)
... self.__dict__.clear()
... self.__dict__.update(state)
... except IndexError:
... pass
...
>>> class A(Transaction3):
... pass
...
>>> a = A()
>>> a.test = 1
>>> a.commit()
>>> a
'self.__dict__ = {'test': 1, 'log': [{'test': 1, 'log': []}]}'
>>> a.other = 2
>>> a
'self.__dict__ = {'test': 1, 'other': 2, 'log': [{'test': 1, 'log': []}]}'
>>> a.rollback()
>>> a
'self.__dict__ = {'test': 1, 'log': []}'
>>> a.other
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'A' object has no attribute 'other'
>>>
```
Ah, works. Very good. Ok, more tests...
```python
>>> b = a.ncls
>>> a.ncls.test = True
>>> a.commit()
>>> a.ncls.test = False
>>> a.rollback()
>>> a
'self.__dict__ = {'ncls': 'self.__dict__ = {'test': True, 'log': []}', 'log': []}'
>>> b
'self.__dict__ = {'test': False, 'log': []}'
```
Oh, what if we work with "b", which stills holds the old value? Maybe we should commit() all our attributes also, traversing through them all? Ok, here is such a beast:
```python
>>> class TransactionNew1(object):
... def _docommit(self):
... if "log" not in self.__dict__:
... self.__dict__["log"] = list()
...
... self.__dict__["log"].append(copy.deepcopy(self.__dict__))
...
... def _dorollback(self):
... if "log" not in self.__dict__:
... return
... try:
... state = self.__dict__["log"].pop(-1)
... self.__dict__.clear()
... self.__dict__.update(state)
... except IndexError:
... pass
...
... def commit(self, **kwargs):
... # commit ourselves, then our childs
... self._docommit()
... if kwargs.get("deep", True):
... for child in self.__dict__.values():
... if isinstance(child, self.__class__):
... child.commit()
...
... def rollback(self, **kwargs):
... # rollback our childs, then ourselves
... if kwargs.get("deep", True):
... for child in self.__dict__.values():
... if isinstance(child, self.__class__):
... child.rollback()
... self._dorollback()
...
... def __repr__(self):
... return "'self.__dict__ = %s'" % self.__dict__
...
>>> class A(TransactionNew1):
... pass
...
>>> a = A()
>>> a.ncls = A()
>>> b = a.ncls
>>> a.ncls.test = True
>>> a.commit()
>>> a.ncls.test = False
>>> a.rollback()
>>> a
'self.__dict__ = {'ncls': 'self.__dict__ = {'test': True}', 'log': []}'
>>> b
'self.__dict__ = {'test': True, 'log': []}'
```
Ok... looks good, but we lost the reference. id(b) != id(a.ncls) ... ( update: this is fixed in the final version ) Working with it revealed also:
```python
>>> a = A()
>>> b = a
>>> for i in xrange(3):
... b.n = A()
... b.t = "test"
... b = b.n
... a.commit()
...
>>> a
'self.__dict__ = {'log': [{'n': 'self.__dict__ = {}', 'log': [], 't': 'test'}, {'n': 'self.__dict__ = {'log': [{'log': []}], 't': 'test', 'n': 'self.__dict__ = {}'}', 'log': [{'t': 'test', 'log': [], 'n': 'self.__dict__ = {}'}], 't': 'test'}, {'n': 'self.__dict__ = {'log': [{'log': []}, {'log': [{'log': []}], 't': 'test', 'n': 'self.__dict__ = {}'}], 't': 'test', 'n': 'self.__dict__ = {'log': [{'log': []}], 't': 'test', 'n': 'self.__dict__ = {}'}'}', 'log': [{'t': 'test', 'log': [], 'n': 'self.__dict__ = {}'}, {'t': 'test', 'log': [{'n': 'self.__dict__ = {}', 't': 'test', 'log': []}], 'n': 'self.__dict__ = {'t': 'test', 'log': [{'log': []}], 'n': 'self.__dict__ = {}'}'}], 't': 'test'}], 't': 'test', 'n': 'self.__dict__ = {'t': 'test', 'log': [{'log': []}, {'n': 'self.__dict__ = {}', 't': 'test', 'log': [{'log': []}]}, {'n': 'self.__dict__ = {'log': [{'log': []}], 't': 'test', 'n': 'self.__dict__ = {}'}', 't': 'test', 'log': [{'log': []}, {'log': [{'log': []}], 't': 'test', 'n': 'self.__dict__ = {}'}]}], 'n': 'self.__dict__ = {'t': 'test', 'log': [{'log': []}, {'n': 'self.__dict__ = {}', 't': 'test', 'log': [{'log': []}]}], 'n': 'self.__dict__ = {'log': [{'log': []}]}'}'}'}'
>>> len(str(a))
1192
```
Hmm... seems strange.. Ah, self.log was also copied with copy.deepcopy(). So, we have multiple useless copies. Let's "pop()" the state from self.__dict__ before the deepcopy.
```python
>>> class TransactionNew2(TransactionNew1):
... def _docommit(self):
... if "log" in self.__dict__:
... oldstate = self.__dict__.pop("log")
... else:
... oldstate = None
... state = copy.deepcopy(self.__dict__)
... if oldstate:
... state["log"] = oldstate
... self.__dict__["log"] = state
... def _dorollback(self):
... if "log" not in self.__dict__:
... return
... try:
... state = self.__dict__["log"]
... self.__dict__.clear()
... self.__dict__.update(state)
... except IndexError:
... pass
...
>>> class A(TransactionNew2):
... pass
...
>>>
>>> a = A()
>>> b = a
>>> for i in xrange(3):
... b.n = A()
... b.t = "test"
... b = b.n
... a.commit()
...
>>> a
'self.__dict__ = {'log': {'log': {'log': {'t': 'test', 'n': 'self.__dict__ = {}'}, 't': 'test', 'n': 'self.__dict__ = {'log': {}, 't': 'test', 'n': 'self.__dict__ = {}'}'}, 't': 'test', 'n': 'self.__dict__ = {'log': {'t': 'test', 'n': 'self.__dict__ = {}'}, 't': 'test', 'n': 'self.__dict__ = {'log': {}, 't': 'test', 'n': 'self.__dict__ = {}'}'}'}, 't': 'test', 'n': 'self.__dict__ = {'t': 'test', 'log': {'log': {'t': 'test', 'n': 'self.__dict__ = {}'}, 't': 'test', 'n': 'self.__dict__ = {'log': {}, 't': 'test', 'n': 'self.__dict__ = {}'}'}, 'n': 'self.__dict__ = {'t': 'test', 'log': {'t': 'test', 'n': 'self.__dict__ = {}'}, 'n': 'self.__dict__ = {'log': {}}'}'}'}'
>>> len(str(a))
671
```
Ok, saved us a bit of state length. The final version has:
```python
>>> a
'self.__dict__ = {'__l': {'__l': {'__l': {'t': 'test'}, 't': 'test'}, 't': 'test'}, 't': 'test', 'n': 'self.__dict__ = {'__l': {'__l': {'t': 'test'}, 't': 'test'}, 't': 'test', 'n': 'self.__dict__ = {'__l': {'t': 'test'}, 't': 'test', 'n': 'self.__dict__ = {'__l': {}}'}'}'}'
>>> len(str(a))
275
```
Now another thing:
```python
>>> a = A()
>>> a.n = a
>>> a.commit()
File "/usr/lib64/python2.5/copy.py", line 162, in deepcopy
y = copier(x, memo)
RuntimeError: maximum recursion depth exceeded
```
... Oh, oh! Recursion in commit()... Now we have to check, if we have been there.
```python
>>> class TransactionNew3(TransactionNew2):
... def _checksetseen(self, seen):
... if id(self) in seen:
... import sys
... sys.stderr.write("Recursion detected... \n")
... return True
... seen.add(id(self))
... return False
...
... def commit(self, **kwargs): # pylint: disable-msg=W0613
... seen = kwargs.get("_commit_seen", set())
... if self._checksetseen(seen):
... return
... # commit ourselves, then our childs
... self._docommit()
... if kwargs.get("deep", True):
... for child in self.__dict__.values():
... if isinstance(child, self.__class__):
... child.commit(_commit_seen = seen)
...
... def rollback(self, **kwargs):
... seen = kwargs.get("_rollback_seen", set())
... if self._checksetseen(seen):
... return
... # rollback our childs, then ourselves
... if kwargs.get("deep", True):
... for child in self.__dict__.values():
... if isinstance(child, self.__class__):
... child.rollback(_rollback_seen = seen)
... self._dorollback()
...
>>>
>>> class A(TransactionNew3):
... pass
...
>>> a = A()
>>> a.n = a
>>> a.commit()
Recursion detected...
>>>
```
The final class with an extension for `__setstate__` and `__getstate__` can be found here: [transaction.py](https://harald.hoyer.xyz/files/transaction.py) and [transaction_test.py](/files/transaction_test.py). Have fun with it :-)

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

5
content/2015/_index.md Normal file
View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,87 @@
+++
title = "GPG, Smartcard and ssh"
date = 2016-07-21T14:35:14+00:00
+++
This blog post shows how to tweak Fedora, if you want to use a smartcard with OpenPGP and use it also as a ssh key.
It also serves me as a recipe for fresh installations.
<!-- more -->
First, you have to disable gnome-keyring-ssh by:
```console
$ cp /etc/xdg/autostart/gnome-keyring-ssh.desktop \
$HOME/.config/autostart
$ echo "Hidden=true" \
>> $HOME/.config/autostart/gnome-keyring-ssh.desktop
```
Because the pcscd daemon does not play nicely with scdaemon from gpg, we have two options.
1. disable pcscd completely (recommended) by
```console
$ sudo systemctl mask --now pcscd.socket
$ sudo systemctl mask --now pcscd.service
```
2. or a `$HOME/.gnupg/scdaemon.conf` with
```properties
pcsc-driver /usr/lib64/libpcsclite.so.1
disable-ccid
```
In `$HOME/.gnupg/gpg.conf` `use-agent` should be enabled (should be the default anyway).
`$HOME/.gnupg/gpg-agent.conf` should have: `enable-ssh-support`
To point ssh to the gpg-agent my `.bashrc` contains the line:
```bash
unset SSH_AGENT_PID
export SSH_AUTH_SOCK=$HOME/.gnupg/S.gpg-agent.ssh
```
on newer systems, this can be
```bash
export SSH_AUTH_SOCK=/run/user/$UID/gnupg/S.gpg-agent.ssh
```
Relogin or reboot to get rid of gnome-keyring-ssh.
Now `gpg2 --card-status` and `ssh-add -L` should work as expected:
```console
$ gpg2 --card-status
Reader ...........: 1050:0116:X:0
Application ID ...: D2760001240102000006045502760000
Version ..........: 2.0
Manufacturer .....: Yubico
Serial number ....: XXXX
Name of cardholder: Harald Hoyer
Language prefs ...: de
Sex ..............: male
URL of public key : hkp://pool.sks-keyservers.net
Login data .......: [not set]
Signature PIN ....: forced
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 3 3
Signature counter : 23
Signature key ....: 8745 5B0B B9F9 CDC3 619D C4FE 7BDB F42F AF81 54A2 created ....: 2016-07-11 18:25:14
Encryption key....: 380C 0F4C A077 779A D4D4 93D6 F3FC E22D CDB8 95CB created ....: 2016-07-11 18:25:14
Authentication key: 8D02 04DF 42FC 2133 8356 DDFB EB09 2344 9913 9572 created ....: 2016-07-11 18:25:14
General key info..: [none]
$ ssh-add -L
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCSMiUCfHXItvZuUP3xO7hjIBukVl9cILSjSapM8WNS8IdyJJrZE00fy30jUwxCeCzSGDMi3WwLlAby99jVyTRgdxb5qHPWaT0k7MmkWLs9vydpZBLLeeyS3KQBrGcwrIA0h0p7A1kCXesiVL6cQCsGMxfQf1YWFBaL5VamXxpfSmz6ia8BEtQJjhJ2NpsyAuAJEs2dPdc5xn/ZRbY+pHV8ruoK0JJdH3c/us6rbrNHKfGnkE5anbKNoMposie3ADjc5ElEFjfAmJ7WxFGvRHA5P51B3jcjSYx4YQvUGq3sW3AhBjfD9VuBIjXDR6B6PKNZSAesWjatTA4fJY1mcw1x cardno:000604550276
```
To forward your gpg-agent and ssh-agent to remote machines, I add the following lines to my .ssh/config:
```properties
RemoteForward /home/harald/.gnupg/S.gpg-agent /home/harald/.gnupg/S.gpg-agent
RemoteForward /home/harald/.gnupg/S.gpg-agent3 /home/harald/.gnupg/S.gpg-agent3
StreamLocalBindUnlink yes
ForwardAgent yes
```
OpenSSH has a [bug](https://bugzilla.mindrot.org/show_bug.cgi?id=2601), so that `StreamLocalBindUnlink yes` does not
work in the client configuration and thus, you have to add that option to the remote server `/etc/ssh/sshd_config`

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,11 @@
+++
title = "dracut and CVE-2016-4484: Cryptsetup Initrd root Shell"
date = 2016-11-15T16:42:23+00:00
+++
People who want to secure their Fedora/RHEL system have to:
* add a BIOS password
* add a grub password
* add "rd.shell=0" to the kernel command line
Anaconda does add "rd.shell=0" to the kernel command line automatically, if you setup the bootloader with a password.
<!-- more -->

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,11 @@
+++
title = "Rust Echo Server"
date = 2016-12-09T14:23:35+00:00
+++
On modern CPUs, rust seems to perform very nicely with the thread context switches,
at least when benchmarking an [echo server](https://github.com/haraldh/rust_echo_server).
For that I also wrote an [echo server benchmark client](https://github.com/haraldh/rust_echo_bench).
<!-- more -->
The [README.md](https://github.com/haraldh/rust_echo_server/blob/master/README.md) of the server also
contains some benchmark numbers.

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

5
content/2016/_index.md Normal file
View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,155 @@
+++
title = "Varlink"
date = 2017-12-18T12:22:38+00:00
+++
For a long time we tried to solve the early boot IPC problem. IPC problem you ask? Well, in the early boot phase we
cannot talk D-BUS, because the daemon is not running yet, but to bring up the system, so that the D-BUS daemon can run
(mount stuff, load modules, start other services), we need some kind of IPC. Therefore all the early boot daemons have a
fallback IPC via unix domain sockets with its own homegrown protocol.
<!-- more -->
### K-DBUS ###
Moving the D-BUS daemon in the kernel was our first approach, but with all the functionality the D-BUS daemon
has (signal broadcasting, etc.), there was no clean solution possible, which satisfied all kernel devs.
### BUS1 ###
BUS1 was written, but turned out overly complex and was just a transport without a protocol.
### Varlink
While BUS1 was developed as a transport, our team was looking for a protocol and tried simplifying the D-BUS protocol.
After a lot of iterations not even the variant data protocol was left. Instead Kay Sievers and Lars Karlitski came up
with a super simple JSON based IPC protocol, which only needs a point-to-point connection, so BUS1 was not even needed.
## KISS
The [varlink](http://varlink.org/) protocol is so simple, that language bindings can be implemented easily and using
varlink does not result into spending more time coding for IPC than for the actual problem.
Bindings for
[C](https://github.com/varlink/libvarlink),
[Javascript](https://github.com/varlink/org.varlink.http),
[Go](https://github.com/varlink/org.varlink.http),
[Java](https://dentrassi.de/2017/12/17/varlink-for-java-what-wonderful-world-it-could-be/),
[Python](https://github.com/varlink/python-varlink)
and [Rust](https://github.com/varlink/rust-varlink) were quickly implemented (some still only as a proof of concept).
[A service for resolving interface](https://github.com/varlink/org.varlink.resolver) names into connection
URLs and starting the executable has been written, which resembles some of the D-BUS functionality of resolving
and activating services.
## APIs
The most important feature of varlink though, is in the interface definition files. They are human readable and can
be even discussed amongst people, which are not developing the implementation. They enable a "checks and balance"
system for product management, customers, quality engineering and software developers. Interface stability and
backwards compatibility can be enforced easily.
To quote the varlink [Ideals page](https://github.com/varlink/documentation/wiki/Ideals):
> ### Simplicity ###
>
> Varlink aims to be as simple as possible. It is not specifically optimized for anything else but ease-of-use and maintainability.
>
> ### [](https://github.com/varlink/documentation/wiki/Ideals#discoverability)Discoverability ###
>
> Varlink services describe themselves; with a machine-readable interface definition, and human-readable documentation.
>
> ### [](https://github.com/varlink/documentation/wiki/Ideals#remotability)Remotability ###
>
> It should be easy to forward, proxy, redirect varlink interfaces over any connection-oriented transport. Varlink should be free of any side-effects of local APIs. All interactions need to be simple messages on a network, not carrying things like file descriptors or references to locally stored files.
>
> ### [](https://github.com/varlink/documentation/wiki/Ideals#focus)Focus ###
>
> Varlink is the protocol and definition of interfaces, but it does not define or provide any significant functionality itself.
>
> ### [](https://github.com/varlink/documentation/wiki/Ideals#errors)Errors ###
>
> Varlink errors should carry enough information to be consumed by machines and automated rules.
>
> ### [](https://github.com/varlink/documentation/wiki/Ideals#testing)Testing ###
>
> Making it easy to run automated tests against varlink interfaces should be considered a necessity when designing interfaces.
Right now the API to a Linux system consists of:
* kernel: ioctls, syscalls, procfs, sysfs
* CLI: options, stdout output to be parsed
* D-BUS, Protobuf, various other IPC, homegrown IPC protocols, …
All these can be replaced by varlink interfaces (yes, even the [kernel interfaces](https://github.com/varlink/linux-varlink)).
Of course varlink is the [15th xkcd standard](https://xkcd.com/927/) here :-P If the adoption of varlink takes off,
then the collection of interfaces could form a common Linux System API.
These interface definitions can be inspected even at runtime via a common interface named `org.varlink.service`,
which every service provides. With this mechanism it is very easy for interpreter languanges
to create bindings at runtime, as we will see in the next chapter.
## Varlink for Python
Ready for some example on how to use varlink with python? First we need some packages to install on Fedora:
```console
$ sudo dnf copr enable "@varlink/varlink"
$ sudo dnf install fedora-varlink
$ sudo setenforce 0 # needed until systemd is able to create sockets in /run
$ sudo systemctl enable --now org.varlink.resolver.socket
$ varlink help
```
In this example, we will call an interface called `com.redhat.system.accounts` which has the following varlink interface:
```varlink
interface com.redhat.accounts
type Account (
name: string,
uid: int,
gid: int,
full_name: string,
home: string,
shell: string
)
# Retrieve a list of account information for all known accounts
method GetAll() -> (accounts: []Account)
# Retrieve the account information for a specific user ID
method GetByUid(uid: int) -> (account: Account)
# Retrieve the account information
method GetByName(name: string) -> (account: Account)
# Add new account
method Add(account: Account) -> (account: Account)
error NotFound ()
error CreationFailed (field: string)
```
From reading the interface definition, the API should be understandable,
even for people, who have never seen a varlink interface file.
Now, let's call the service from some python code:
```python
from varlink import Client
client = Client(resolve_interface='com.redhat.accounts')
accounts = client.open('com.redhat.accounts', namespaced=True)
ret = accounts.GetByName("root")
print(ret)
```
will output:
```python
namespace(account=namespace(full_name='root', gid=0, home='/root', name='root', shell='/bin/bash', uid=0))
```
and
```python
>> print(ret.account.full_name, ret.account.uid, ret.account.shell)
```
will output:
```
root 0 /bin/bash
```
That's it! And the varlink python module is also very small.
Stay tuned for more and go read [Jens Reinmann's Java Varlink blog post](https://dentrassi.de/2017/12/17/varlink-for-java-what-wonderful-world-it-could-be/).

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

5
content/2017/_index.md Normal file
View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,16 @@
+++
title = "varlink and the elvish shell"
date = 2018-02-22T09:53:37+00:00
+++
I recently discovered [Elvish](https://elvish.io/), which is a shell perfectly
suited to process structured data. In my case it is perfect to be used with
[varlink](http://varlink.org). Too bad elvish has no numeric type and
can't feed varlink with int and float, because to\-json converts them to strings.
<!-- more -->
<img src=https://harald.hoyer.xyz/wp-content/uploads/sites/2/2018/02/Screenshot-from-2018-02-22-11-07-04.png>
To see what I mean, watch this video:
[![video preview](/img/elvis-varlink-screencast.png)](https://asciinema.org/a/bB3OatlJltV3tTdSRpsrQELxQ).

View file

@ -0,0 +1,6 @@
+++
title = "varlink for dnf - a Showcase"
date = 2018-02-22T07:09:03+00:00
+++
On the [varlink wiki page](https://github.com/varlink/documentation/wiki/Adding-varlink-to-DNF) I showcase how to add varlink to a python project. In this case, I chose DNF, the rpm package manager of Fedora.
<!-- more -->

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

5
content/2018/_index.md Normal file
View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

View file

@ -0,0 +1,84 @@
+++
title = "Bat understands varlink now"
date = 2019-02-07T07:04:47+00:00
+++
[Bat](https://github.com/sharkdp/bat) is a *cat(1)* clone with syntax highlighting and Git integration.
My pull request for varlink syntax coloring was accepted today :\-)
<!-- more -->
So, to display:
```varlink
# The Varlink Service Interface is provided by every varlink service. It
# describes the service and the interfaces it implements.
interface org.varlink.service
# Get a list of all the interfaces a service provides and information
# about the implementation.
method GetInfo() -> (
vendor: string,
product: string,
version: string,
url: string,
interfaces: []string
)
# Get the description of an interface that is implemented by this service.
method GetInterfaceDescription(interface: string) -> (description: string)
# The requested interface was not found.
error InterfaceNotFound (interface: string)
# The requested method was not found
error MethodNotFound (method: string)
# The interface defines the requested method, but the service does not
# implement it.
error MethodNotImplemented (method: string)
# One of the passed parameters is invalid.
error InvalidParameter (parameter: string)
```
it will look like this:
<pre style="background-color: black;color: white"><b>$</b> bat org.varlink.service.varlink
<font color="#444444">───────┬───────────────────────────────────────────────────────────────────────────────</font>
<font color="#444444"></font>File: <b>org.varlink.service.varlink</b>
<font color="#444444">───────┼───────────────────────────────────────────────────────────────────────────────</font>
<font color="#444444"> 1</font> <font color="#444444"></font> <font color="#75715E"># The Varlink Service Interface is provided by every varlink service. It</font>
<font color="#444444"> 2</font> <font color="#444444"></font> <font color="#75715E"># describes the service and the interfaces it implements.</font>
<font color="#444444"> 3</font> <font color="#444444"></font> <font color="#66D9EF">interface</font><font color="#F8F8F2"> </font><font color="#A6E22E">org.varlink.service</font>
<font color="#444444"> 4</font> <font color="#444444"></font>
<font color="#444444"> 5</font> <font color="#444444"></font> <font color="#75715E"># Get a list of all the interfaces a service provides and information</font>
<font color="#444444"> 6</font> <font color="#444444"></font> <font color="#75715E"># about the implementation.</font>
<font color="#444444"> 7</font> <font color="#444444"></font> <font color="#66D9EF">method</font><font color="#F8F8F2"> </font><font color="#A6E22E">GetInfo</font><font color="#F8F8F2">() </font><font color="#F92672">-&gt; </font><font color="#F8F8F2">(</font>
<font color="#444444"> 8</font> <font color="#444444"></font> <font color="#F8F8F2"> </font><font color="#FD971F">vendor</font><font color="#F8F8F2">: </font><font color="#66D9EF">string</font><font color="#F8F8F2">,</font>
<font color="#444444"> 9</font> <font color="#444444"></font> <font color="#F8F8F2"> </font><font color="#FD971F">product</font><font color="#F8F8F2">: </font><font color="#66D9EF">string</font><font color="#F8F8F2">,</font>
<font color="#444444"> 10</font> <font color="#444444"></font> <font color="#F8F8F2"> </font><font color="#FD971F">version</font><font color="#F8F8F2">: </font><font color="#66D9EF">string</font><font color="#F8F8F2">,</font>
<font color="#444444"> 11</font> <font color="#444444"></font> <font color="#F8F8F2"> </font><font color="#FD971F">url</font><font color="#F8F8F2">: </font><font color="#66D9EF">string</font><font color="#F8F8F2">,</font>
<font color="#444444"> 12</font> <font color="#444444"></font> <font color="#F8F8F2"> </font><font color="#FD971F">interfaces</font><font color="#F8F8F2">: </font><font color="#F92672">[]</font><font color="#66D9EF">string</font>
<font color="#444444"> 13</font> <font color="#444444"></font> <font color="#F8F8F2">)</font>
<font color="#444444"> 14</font> <font color="#444444"></font>
<font color="#444444"> 15</font> <font color="#444444"></font> <font color="#75715E"># Get the description of an interface that is implemented by this service.</font>
<font color="#444444"> 16</font> <font color="#444444"></font> <font color="#66D9EF">method</font><font color="#F8F8F2"> </font><font color="#A6E22E">GetInterfaceDescription</font><font color="#F8F8F2">(</font><font color="#FD971F">interface</font><font color="#F8F8F2">: </font><font color="#66D9EF">string</font><font color="#F8F8F2">) </font><font color="#F92672">-&gt; </font><font color="#F8F8F2">(</font><font color="#FD971F">description</font><font color="#F8F8F2">: </font><font color="#66D9EF">string</font><font color="#F8F8F2">)</font>
<font color="#444444"> 17</font> <font color="#444444"></font>
<font color="#444444"> 18</font> <font color="#444444"></font> <font color="#75715E"># The requested interface was not found.</font>
<font color="#444444"> 19</font> <font color="#444444"></font> <font color="#66D9EF">error</font><font color="#F8F8F2"> </font><font color="#A6E22E">InterfaceNotFound</font><font color="#F8F8F2"> (</font><font color="#FD971F">interface</font><font color="#F8F8F2">: </font><font color="#66D9EF">string</font><font color="#F8F8F2">)</font>
<font color="#444444"> 20</font> <font color="#444444"></font>
<font color="#444444"> 21</font> <font color="#444444"></font> <font color="#75715E"># The requested method was not found</font>
<font color="#444444"> 22</font> <font color="#444444"></font> <font color="#66D9EF">error</font><font color="#F8F8F2"> </font><font color="#A6E22E">MethodNotFound</font><font color="#F8F8F2"> (</font><font color="#FD971F">method</font><font color="#F8F8F2">: </font><font color="#66D9EF">string</font><font color="#F8F8F2">)</font>
<font color="#444444"> 23</font> <font color="#444444"></font>
<font color="#444444"> 24</font> <font color="#444444"></font> <font color="#75715E"># The interface defines the requested method, but the service does not</font>
<font color="#444444"> 25</font> <font color="#444444"></font> <font color="#75715E"># implement it.</font>
<font color="#444444"> 26</font> <font color="#444444"></font> <font color="#66D9EF">error</font><font color="#F8F8F2"> </font><font color="#A6E22E">MethodNotImplemented</font><font color="#F8F8F2"> (</font><font color="#FD971F">method</font><font color="#F8F8F2">: </font><font color="#66D9EF">string</font><font color="#F8F8F2">)</font>
<font color="#444444"> 27</font> <font color="#444444"></font>
<font color="#444444"> 28</font> <font color="#444444"></font> <font color="#75715E"># One of the passed parameters is invalid.</font>
<font color="#444444"> 29</font> <font color="#444444"></font> <font color="#66D9EF">error</font><font color="#F8F8F2"> </font><font color="#A6E22E">InvalidParameter</font><font color="#F8F8F2"> (</font><font color="#FD971F">parameter</font><font color="#F8F8F2">: </font><font color="#66D9EF">string</font><font color="#F8F8F2">)</font>
<font color="#444444">───────┴───────────────────────────────────────────────────────────────────────────────</font>
</pre>

View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

5
content/2019/_index.md Normal file
View file

@ -0,0 +1,5 @@
+++
transparent = true
sort_by = "date"
paginate_by = 5
+++

4
content/_index.md Normal file
View file

@ -0,0 +1,4 @@
+++
paginate_by = 5
sort_by = "date"
+++

3
content/pages/_index.md Normal file
View file

@ -0,0 +1,3 @@
+++
render = false
+++

View file

@ -0,0 +1,23 @@
+++
title = "Impressum"
path = "impressum"
date = 2000-01-01
template = "impressum.html"
+++
# Impressum
Harald Hoyer
Gerda-Penzel-Str. 13
85591 Vaterstetten
Email:webmaster@harald.hoyer.xyz
GPG key: current [0x4BC0896FB5693595](https://harald.hoyer.xyz/files/gpg-key.txt) as seen on the key servers and [people.redhat.com](https://people.redhat.com/harald/gpg-pub-7F3D64824AC0B6B8009E50504BC0896FB5693595.asc)
Keybase: [https://keybase.io/haraldhoyer/](https://keybase.io/haraldhoyer/)
old GPG key (not compromised): C5575542 as seen on the key servers

BIN
static/img/about-bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

BIN
static/img/contact-bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
static/img/home-bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

BIN
static/img/post-bg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,95 @@
%YAML 1.2
---
name: varlink
file_extensions:
- varlink
scope: source.varlink
variables:
interface_name: '([a-z](\-*[a-z0-9])*(\.[a-z0-9](\-*[a-z0-9])*)+)'
identifier: '([A-Z][a-zA-Z0-9_]*)'
field_name: '[A-Za-z]([_]?[A-Za-z0-9])*'
contexts:
main:
- include: statements
statements:
- include: comments
- match: '(interface)\s+(\b{{interface_name}}\b)'
scope: meta.type.declaration.varlink
captures:
1: storage.type.interface.varlink
2: entity.name.interface.varlink
- match: '(method)\s+(\b{{identifier}}\b)\s*(?=[(])'
scope: meta.method.declaration.varlink
captures:
1: storage.type.method.varlink
2: entity.name.method.varlink
push: [ method-return, block ]
- match: '(type)\s+(\b{{identifier}}\b)\s*(?=[(])'
scope: meta.type.declaration.varlink
captures:
1: storage.type.type.varlink
2: entity.name.type.varlink
push: block
- match: '(error)\s+(\b{{identifier}}\b)\s*(?=[(])'
scope: meta.error.declaration.varlink
captures:
1: storage.type.error.varlink
2: entity.name.error.varlink
push: block
method-return:
- match: '(->)\s*(?=[(])'
scope: keyword.operator.varlink
set: block
block:
- include: comments
- match: '\)'
scope: punctuation.section.group.end.varlink
pop: true
- match: '\('
scope: punctuation.section.group.begin.varlink
push: block-inner
block-inner:
- include: comments
- match: '(?=\))'
pop: true
- match: '\b{{field_name}}\b'
scope: variable.parameter.varlink
- match: ','
scope: punctuation.separator.varlink
- match: ":"
scope: punctuation.separator.varlink
push: type
type:
- include: comments
- match: '(?=\()'
push: block
- match: '(?=\))'
pop: true
- match: '(?=,)'
pop: true
- match: '\b(string|bool|int|float|object)\b'
scope: storage.type.varlink
- match: '(\[\]|\[string\]|\?)'
scope: storage.modifier.varlink
- match: '\b{{identifier}}\b'
scope: entity.name.type.varlink
comments:
- match: "#"
scope: punctuation.definition.comment.varlink
push:
- meta_scope: comment.line.documentation.varlink
- match: $\n?
pop: true