initial commit
This commit is contained in:
commit
429a176559
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
/public
|
||||||
|
/.idea/
|
||||||
|
/blog.iml
|
56
config.toml
Normal file
56
config.toml
Normal 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"}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
5
content/2013/11/04/_index.md
Normal file
5
content/2013/11/04/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
18
content/2013/11/04/dracut-kernel-command-line.md
Normal file
18
content/2013/11/04/dracut-kernel-command-line.md
Normal 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.
|
5
content/2013/11/07/_index.md
Normal file
5
content/2013/11/07/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
|
@ -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) :\-)
|
5
content/2013/11/13/_index.md
Normal file
5
content/2013/11/13/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
152
content/2013/11/13/fedora-boot-optimization.md
Normal file
152
content/2013/11/13/fedora-boot-optimization.md
Normal 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!
|
17
content/2013/11/13/linux-howto-get-the-number-of-cpus.md
Normal file
17
content/2013/11/13/linux-howto-get-the-number-of-cpus.md
Normal 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.
|
5
content/2013/11/_index.md
Normal file
5
content/2013/11/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2013/_index.md
Normal file
5
content/2013/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2014/01/14/_index.md
Normal file
5
content/2014/01/14/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
71
content/2014/01/14/self-hosting-fedora-base.md
Normal file
71
content/2014/01/14/self-hosting-fedora-base.md
Normal 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
|
5
content/2014/01/_index.md
Normal file
5
content/2014/01/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2014/_index.md
Normal file
5
content/2014/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2015/02/25/_index.md
Normal file
5
content/2015/02/25/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
|
@ -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! :-)
|
5
content/2015/02/_index.md
Normal file
5
content/2015/02/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2015/03/05/_index.md
Normal file
5
content/2015/03/05/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
|
@ -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).
|
5
content/2015/03/_index.md
Normal file
5
content/2015/03/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2015/10/13/_index.md
Normal file
5
content/2015/10/13/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
357
content/2015/10/13/a-python-transaction-class.md
Normal file
357
content/2015/10/13/a-python-transaction-class.md
Normal 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 :-)
|
5
content/2015/10/_index.md
Normal file
5
content/2015/10/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2015/_index.md
Normal file
5
content/2015/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2016/07/21/_index.md
Normal file
5
content/2016/07/21/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
87
content/2016/07/21/gpg-smartcard-and-ssh.md
Normal file
87
content/2016/07/21/gpg-smartcard-and-ssh.md
Normal 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`
|
5
content/2016/07/_index.md
Normal file
5
content/2016/07/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2016/11/15/_index.md
Normal file
5
content/2016/11/15/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
|
@ -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 -->
|
5
content/2016/11/_index.md
Normal file
5
content/2016/11/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2016/12/09/_index.md
Normal file
5
content/2016/12/09/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
11
content/2016/12/09/rust-echo-server.md
Normal file
11
content/2016/12/09/rust-echo-server.md
Normal 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.
|
5
content/2016/12/_index.md
Normal file
5
content/2016/12/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2016/_index.md
Normal file
5
content/2016/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2017/12/18/_index.md
Normal file
5
content/2017/12/18/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
155
content/2017/12/18/varlink.md
Normal file
155
content/2017/12/18/varlink.md
Normal 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/).
|
5
content/2017/12/_index.md
Normal file
5
content/2017/12/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2017/_index.md
Normal file
5
content/2017/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2018/02/22/_index.md
Normal file
5
content/2018/02/22/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
16
content/2018/02/22/varlink-and-the-elvish-shell.md
Normal file
16
content/2018/02/22/varlink-and-the-elvish-shell.md
Normal 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).
|
6
content/2018/02/22/varlink-for-dnf-a-showcase.md
Normal file
6
content/2018/02/22/varlink-for-dnf-a-showcase.md
Normal 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 -->
|
5
content/2018/02/_index.md
Normal file
5
content/2018/02/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2018/_index.md
Normal file
5
content/2018/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2019/02/07/_index.md
Normal file
5
content/2019/02/07/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
84
content/2019/02/07/bat-understands-varlink-now.md
Normal file
84
content/2019/02/07/bat-understands-varlink-now.md
Normal 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">-> </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">-> </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>
|
||||||
|
|
||||||
|
|
||||||
|
|
5
content/2019/02/_index.md
Normal file
5
content/2019/02/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
5
content/2019/_index.md
Normal file
5
content/2019/_index.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
+++
|
||||||
|
transparent = true
|
||||||
|
sort_by = "date"
|
||||||
|
paginate_by = 5
|
||||||
|
+++
|
4
content/_index.md
Normal file
4
content/_index.md
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
+++
|
||||||
|
paginate_by = 5
|
||||||
|
sort_by = "date"
|
||||||
|
+++
|
3
content/pages/_index.md
Normal file
3
content/pages/_index.md
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
+++
|
||||||
|
render = false
|
||||||
|
+++
|
23
content/pages/impressum.md
Normal file
23
content/pages/impressum.md
Normal 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
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
BIN
static/img/contact-bg.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 146 KiB |
BIN
static/img/elvis-varlink-screencast.png
Normal file
BIN
static/img/elvis-varlink-screencast.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 34 KiB |
BIN
static/img/home-bg.jpg
Normal file
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
BIN
static/img/post-bg.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.8 MiB |
1228
syntaxes/Sublime-console/commands-builtin-shell-bash.sublime-syntax
Normal file
1228
syntaxes/Sublime-console/commands-builtin-shell-bash.sublime-syntax
Normal file
File diff suppressed because it is too large
Load diff
1408
syntaxes/Sublime-console/console.sublime-syntax
Normal file
1408
syntaxes/Sublime-console/console.sublime-syntax
Normal file
File diff suppressed because it is too large
Load diff
95
syntaxes/Sublime-varlink/varlink.sublime-syntax
Normal file
95
syntaxes/Sublime-varlink/varlink.sublime-syntax
Normal 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
|
||||||
|
|
Loading…
Reference in a new issue