initial commit
This commit is contained in:
		
						commit
						429a176559
					
				
					 59 changed files with 4097 additions and 0 deletions
				
			
		
							
								
								
									
										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: | ||||
|   | ||||
|  [](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…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Harald Hoyer
						Harald Hoyer