<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ivucica blog</title>
	<atom:link href="https://blog.vucica.net/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.vucica.net</link>
	<description>a programmer&#039;s thoughts</description>
	<lastBuildDate>Wed, 13 Aug 2025 13:14:29 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.2</generator>

<image>
	<url>https://blog.vucica.net/wp-content/uploads/2019/02/cropped-bg_1024-32x32.jpg</url>
	<title>ivucica blog</title>
	<link>https://blog.vucica.net</link>
	<width>32</width>
	<height>32</height>
</image> 
<atom:link rel="hub" href="https://pubsubhubbub.superfeedr.com"/><atom:link rel="hub" href="https://pubsubhubbub.appspot.com"/><site xmlns="com-wordpress:feed-additions:1">20982723</site>	<item>
		<title>Random notes on GNOME, GDM3, systemd &#8211;user and ephemeral environment variables such as SSH_AUTH_SOCK</title>
		<link>https://blog.vucica.net/2022/06/random-notes-on-gnome-gdm3-systemd-user-and-ephemeral-environment-variables-such-as-ssh_auth_sock.html</link>
					<comments>https://blog.vucica.net/2022/06/random-notes-on-gnome-gdm3-systemd-user-and-ephemeral-environment-variables-such-as-ssh_auth_sock.html#respond</comments>
		
		<dc:creator><![CDATA[Ivan Vučica]]></dc:creator>
		<pubDate>Wed, 29 Jun 2022 16:21:51 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[troubleshooting]]></category>
		<category><![CDATA[unix]]></category>
		<category><![CDATA[X11]]></category>
		<category><![CDATA[gnome3]]></category>
		<category><![CDATA[systemd]]></category>
		<category><![CDATA[xsession]]></category>
		<guid isPermaLink="false">https://blog.vucica.net/?p=5811</guid>

					<description><![CDATA[This is totally a thought dump, as I just spent hours (!) figuring out why my environment had been persistently setting SSH_AUTH_SOCK across login sessions. It’s not a solution for readers’ particular issues, nor a tutorial on how to resolve my particular issue either: just a log of surprising things I found out today about [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>This is totally a thought dump, as I just spent hours (!) figuring out why my environment had been persistently setting <code>SSH_AUTH_SOCK</code> across login sessions. It’s not a solution for readers’ particular issues, nor a tutorial on how to resolve my particular issue either: just a log of surprising things I found out today about a machine I’m, using.</p>
<hr />
<p>The managed machine I’m using has switched to GDM3 as the display manager, and the default environment is GNOME3. I don’t enjoy GNOME3, and prefer i3 for work uses. I gave it a chance, but after restoring my homedir, I decided to go back to i3.</p>
<p>Note: During the homedir restoration, I had the GNOME3 session running. I moved my homedir away, signed out, and rsynced away. I hope this order of operation got GNOME3 confused and made it forget to clean things up.</p>
<p>Symptom: tools have been complaining they can’t talk to a valid-looking value for <code>SSH_AUTH_SOCK</code>. The socket file and its directory were both missing. <code>ssh-agent</code> was not running in the session.</p>
<ul>
<li>I use <code>~/.Xsession</code> to configure my graphical session before starting i3. My first suspicion was something ran, set <code>SSH_AUTH_SOCK</code> and the <code>ssh-agent</code> crashed afterwards. This was not the case.</li>
<li>I still had the terminal session running. It had an <code>ssh-agent</code> in it. Could that be the cause? No, after nuking the terminal session and signing in and out in the graphical one, the issue was stil present.</li>
<li>Was <code>~/.Xsession</code> supposed to execute <code>/etc/X11/Xsession</code>? No, that happens separately. This is fine.</li>
<li>Is <code>/etc/X11/Xsession.d/90x11-common_ssh-agent</code> getting executed? Yes, it is. But <code>$STARTUP</code> is not getting updated. (Oh, right: <code>/etc/X11/Xsession.d scripts on Debian OSes are not executing things directly, but scheduling later execution by updating envvar</code>STARTUP`.)</li>
<li>Is <code>/etc/X11/Xsession</code> getting executed at all? At what point is <code>SSH_AUTH_SOCK</code> set? No, we are not running it at all. <code>lightdm</code> did (I think), but <code>gdm3</code> has to be a special puppy.</li>
<li>What’s executed instead? <code>/etc/gdm3/Xsession</code> which closely resembles <code>/etc/X11/Xsession</code>, but is not exactly the same.</li>
<li>Is <code>/etc/gdm3/Xsession</code> executing <code>/etc/X11/Xsession.d</code> scripts? Yes, it is.</li>
<li>So, which of the scripts is setting <code>SSH_AUTH_SOCK</code>? Well, in my individual situation, it looks like it’s happening before any of the script executes.</li>
<li>Something in <code>~/.config</code>? No. Envvar name or value not found.</li>
<li>Something in <code>~/.local</code>? No. Envvar name or value not found.</li>
<li>Is something else run? Well, <code>gnome-keychain-daemon</code> is running for some reason and gets restarted upon session restart. It’s run by <code>/etc/xdg/autostart/gnome-keyring-secrets.desktop</code> file, and can be disabled by putting
<pre class="syntax">
[Desktop Entry]
Hidden=true
# maybe other fields are required too?
</pre>
<p>into <code>~/.config/autostart/gnome-keyring-secrets.desktop</code>, blocking system file from starting up. (Remember, this is a managed machine; even if it weren’t, I don’t want to touch distribution-installed files.)</p>
<p>However, no, blocking <code>gnome-keyring-daemon</code> from starting up doesn’t fix the issue.</p>
</li>
</ul>
<p>So this is very confusing. A bad environment variable is surviving logout and seems set before any <code>Xsession</code> script is run.</p>
<p>Is <code>gdm3</code> remembering things for us? Where would it be writing them anyway if not into homedir?</p>
<p>Turns out that no. <code>gdm3</code> isn’t remembering anything.</p>
<hr />
<p><strong>Here’s what happened.</strong></p>
<p><code>systemd</code> can run in per-user mode (<code>systemd --user</code>). It keeps the environment in RAM and can also survive logouts. <code>systemd --user</code> is shared between all logged-in sessions of the current users.</p>
<p>The feature that caused trouble is — management of environment for daemons. <code>systemctl --user show-environment</code> shows that something wrote the entire environment of the GNOME3 session into <code>systemd --user</code>‘s environment. From what I can tell, all daemons started after login will inherit the environment from this. And it had rather ephemeral things like <code>SSH_AUTH_SOCK</code>, <code>XAUTHORITY</code> <code>GPG_AGENT_INFO</code> or <code>XDG_SESSION_DESKTOP</code> written into it!</p>
<p>Killing <code>systemd --user</code> process and restarting the session fixed everything. <code>/etc/gdm3/Xsession</code> no longer had <code>SSH_AUTH_SOCK</code> set when it started (in fact, it was not set by the time <code>/etc/X11/Xsession.d/99x11-common_start</code> was starting to read the <code>$STARTUP</code> envvar.</p>
<p>So, something in GNOME3 decided to write very ephemeral environment variables into <code>systemd --user</code>, never cleaned them up, and <code>systemd --user</code> did not get reaped even after I signed out from both the graphical and the terminal sessions! There’s a chance cleanup of <code>systemd --user</code> did not happen because the homedir was moved away at the time, but isn’t this stuff working with environment variables such as <code>DBUS_SESSION_BUS_ADDRESS</code> envvar, <code>cat /run/systemd/user/$(id -u)</code>, <code>/run/user/$(id -u)</code> and other files under <code>/run</code>? How would have moving <code>/home/${LOGNAME}</code> prevented reaping of <code>systemd --user</code>?</p>
<hr />
<p>I can see some value in these things being per-user rather than per-session, but given how <code>systemd</code> has been pushing for per-session stuff too, this is leaving a bad taste in the mouth, and makes me believe even further that <code>systemd</code> should not try to be “the runtime for Linux” (note, not the other OSes), it should not infect user sessions, and it should simply stick to what it does reasonably well: manage service startup. I really only want the ability to mount a mountpoint after a service has started, and to start a service after a mountpoint appeared. And otherwise similar dependencies on devices, perhaps.</p>
<p>I really don’t appreciate <code>systemd</code> getting into the business of managing cross-session environment variables. Is this why modern free software desktops refuse to start more than one session for a single user? I suspect so.</p>
<p>Previously, I didn’t think whatever we gained by giving up multiple-sessions-per-user was worth it, and after today, I’m not quite encouraged to give up on this gut feeling.</p>
<div class="plus-one-wrap"><g:plusone href="https://blog.vucica.net/2022/06/random-notes-on-gnome-gdm3-systemd-user-and-ephemeral-environment-variables-such-as-ssh_auth_sock.html"></g:plusone></div>]]></content:encoded>
					
					<wfw:commentRss>https://blog.vucica.net/2022/06/random-notes-on-gnome-gdm3-systemd-user-and-ephemeral-environment-variables-such-as-ssh_auth_sock.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5811</post-id>	</item>
		<item>
		<title>How do headsets know they may trigger Google Assistant or Siri? (Notes on AT+BRSF and AT+BVRA)</title>
		<link>https://blog.vucica.net/2022/01/how-do-headsets-know-they-may-trigger-google-assistant-or-siri.html</link>
					<comments>https://blog.vucica.net/2022/01/how-do-headsets-know-they-may-trigger-google-assistant-or-siri.html#comments</comments>
		
		<dc:creator><![CDATA[Ivan Vučica]]></dc:creator>
		<pubDate>Thu, 27 Jan 2022 22:35:12 +0000</pubDate>
				<category><![CDATA[Apple]]></category>
		<category><![CDATA[Bluetooth]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[troubleshooting]]></category>
		<category><![CDATA[unix]]></category>
		<category><![CDATA[bluetooth]]></category>
		<category><![CDATA[button]]></category>
		<category><![CDATA[combadge]]></category>
		<category><![CDATA[voice control]]></category>
		<guid isPermaLink="false">https://blog.vucica.net/?p=5797</guid>

					<description><![CDATA[I don’t know what the Bose QC35-ii is doing: the Action button refuses to do anything unless it’s sure it’s talking to either Google Assistant or Alexa (no Siri mentioned in the app, interestingly). I can’t get the 2021 version of the Star Trek TNG Bluetooth Combadge to trigger anything when connected to a Linux [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>I don’t know what the Bose QC35-ii is doing: the Action button refuses to do anything unless it’s sure it’s talking to either Google Assistant or Alexa (no Siri mentioned in the app, interestingly).</p>
<p>I can’t get the <a href="https://www.fametek.com/products/bluetoothcommunicator">2021 version of the Star Trek TNG Bluetooth Combadge</a> to trigger anything when connected to a Linux machine. The regular press is triggering KEY_PLAYCD and KEY_PAUSECD, thus mapping onto the relevant X events and interacting well with my desktop’s media players (particularly Chrome) — but doublepress, which normally activates Siri on my iPad, sends no input device events on the relevant <code>/dev/input/event*</code> special file. There’s just no traffic.</p>
<p><code>btmon</code> is an interesting discovery, and it pointed me in the direction of the world of AT commands flowing as ACL Data on my local <code>hci0</code> device. Many of the ones flowing are documented on <a href="https://radekp.github.io/qtmoko/api/modememulator-controlandstatus.html">Qt Extended’s modem emulator component documentation from 2009</a>: it starts with the combadge sending <code>AT+BRSF</code> and seeing a response, then sending <code>AT+CIDN</code> and getting and response, and so on and on and on.</p>
<p><a href="https://blog.vucica.net/wp-content/uploads/2022/01/Screenshot-from-2022-01-27-22-05-02.png"><img fetchpriority="high" decoding="async" src="https://blog.vucica.net/wp-content/uploads/2022/01/Screenshot-from-2022-01-27-22-05-02-300x214.png" alt="" width="300" height="214" class="aligncenter size-medium wp-image-5802" srcset="https://blog.vucica.net/wp-content/uploads/2022/01/Screenshot-from-2022-01-27-22-05-02-300x214.png 300w, https://blog.vucica.net/wp-content/uploads/2022/01/Screenshot-from-2022-01-27-22-05-02-768x548.png 768w, https://blog.vucica.net/wp-content/uploads/2022/01/Screenshot-from-2022-01-27-22-05-02-624x446.png 624w, https://blog.vucica.net/wp-content/uploads/2022/01/Screenshot-from-2022-01-27-22-05-02.png 787w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p><a href="https://blog.vucica.net/wp-content/uploads/2022/01/Screenshot-from-2022-01-27-22-02-54.png"><img decoding="async" src="https://blog.vucica.net/wp-content/uploads/2022/01/Screenshot-from-2022-01-27-22-02-54-300x166.png" alt="" width="300" height="166" class="aligncenter size-medium wp-image-5800" srcset="https://blog.vucica.net/wp-content/uploads/2022/01/Screenshot-from-2022-01-27-22-02-54-300x166.png 300w, https://blog.vucica.net/wp-content/uploads/2022/01/Screenshot-from-2022-01-27-22-02-54-624x345.png 624w, https://blog.vucica.net/wp-content/uploads/2022/01/Screenshot-from-2022-01-27-22-02-54.png 752w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>If I am reading everything right, the values returned are decimal numbers representing a binary mask. <code>btmon</code> output seems to indicate the combadge (‘hands-free’ device) claims it supports 127 (i.e. all 8 functionalities in the Modem Emulator docs), and the desktop (‘audio gateway’) says it supports 1536, which is binary 110 0000 0000, meaning the only bits that are set are in the reserved range from the perspective of the 2009 Modem Emulator documentation.</p>
<p>A list of flags can also be found in 2013 <a href="https://github.com/pauloborges/bluez/blob/c6e0cd5/test/test-hfp#L30-L48">bluez test for HFP</a>. Over there, one of the formerly ‘reserved’ bits is specified as being <code>AG_CODEC_NEGOTIATION</code>, but we can luckily find the other one in ChromiumOS’s source code: inside something called <code>adhd</code> (apparently, ChromiumOS Audio Daemon) and its <code>cras</code> component’s server part, the constants are in <a href="https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/third_party/adhd/cras/src/server/cras_hfp_slc.h;l=37-38;drc=c4a5594a292a8719d25d031c1b8ba35c0ae53c87">cras_hfp_slc.h</a>. So, the other bit the desktop claims to support is <code>AG_HF_INDICATORS</code>, which also has nothing to do with remote control.</p>
<p>That source code also indicates we can read the Hands-Free Profile specification, the latest one being version 1.8 <a href="https://www.bluetooth.com/specifications/specs/">available on Bluetooth.com</a>.</p>
<p>So, if I am interpreting everything correctly, the combadge says it supports “everything”, but the desktop doesn’t tell it back that it knows what voice recognition is. No wonder we’re not seeing any traffic.</p>
<p>So, we don’t quite need to support Apple-specific HFP commands such as <code>AT+XAPL</code> (bluetooth accessory identification), <code>AT+APLSIRI</code> (confirming the device supports specifically Siri) or <code>AT+IPHONEACCEV</code> (sharing battery level), which is nice. Both of the platforms documented by the combadge’s marketing materials and the manual (Google Now i.e. Assistant and Siri) document they support <code>AT+BVRA</code> from the Hands-Free Profile specification; see Google Assistant’s <a href="https://developers.google.com/assistant/accessories/integrate/bluetooth/voice-optimization">“Voice Activation Optimization” document</a> for Bluetooth devices, as well as the <a href="https://developer.apple.com/accessories/Accessory-Design-Guidelines.pdf">“Accessory Design Guidelines for Apple Devices</a> (release R16 talks about this in section 30.3.1).</p>
<p>Instead, it looks like we mainly need to trick the desktop to respond to combadge’s <code>AT+BRSF</code> request with a bitmask that includes the voice recognition bit, and move on from that, hoping the combadge starts emitting <code>AT+BVRA</code>, and that we can easily programmatically capture that!</p>
<p>But that’s a topic for another post.</p>
<p><!-- 
todo:

- ofono might implement the relevant org.bluez interfaces. https://lists.01.org/hyperkitty/list/ofono@ofono.org/thread/IFCYQ7YH6MCXA5XWMAHT4KUFACC2QOSK/ 
- a predecessor of the relevant interfaces: https://whitequark.livejournal.com/20590.html
- https://www.spinics.net/lists/linux-bluetooth/msg11303.html 
- also https://stackoverflow.com/questions/67004099/how-to-implement-hfp-on-linux-with-bluez
- non-linux work: https://programmer.help/blogs/qcc300x-learning-notes-custom-hfp-at-command.html
- some chatter but unanswered: https://www.spinics.net/lists/linux-bluetooth/msg62596.html
- patches for pulseaudio: https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/94
- also https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/491
- chatter from authors of one patchset https://lore.kernel.org/linux-bluetooth/20191201185740.uot7zb2s53p5gu7z@pali/T/#u
- prototype: https://github.com/pali/hsphfpd-prototype
- with pipewire, this was needed to make audio work in the first place: libspa-0.2-bluetooth, so maybe the work that went into pulseaudio is not relevant?
- pipewire work: https://gitlab.freedesktop.org/pipewire/pipewire/-/tree/master/spa/plugins/bluez5
--></p>
<div class="plus-one-wrap"><g:plusone href="https://blog.vucica.net/2022/01/how-do-headsets-know-they-may-trigger-google-assistant-or-siri.html"></g:plusone></div>]]></content:encoded>
					
					<wfw:commentRss>https://blog.vucica.net/2022/01/how-do-headsets-know-they-may-trigger-google-assistant-or-siri.html/feed</wfw:commentRss>
			<slash:comments>4</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5797</post-id>	</item>
		<item>
		<title>ddwrt router refusing to forward multicast packets over an OpenVPN tap device joined to a bridge</title>
		<link>https://blog.vucica.net/2020/11/ddwrt-router-refusing-to-forward-multicast-packets-over-an-openvpn-tap-device-joined-to-a-bridge.html</link>
					<comments>https://blog.vucica.net/2020/11/ddwrt-router-refusing-to-forward-multicast-packets-over-an-openvpn-tap-device-joined-to-a-bridge.html#respond</comments>
		
		<dc:creator><![CDATA[Ivan Vučica]]></dc:creator>
		<pubDate>Thu, 26 Nov 2020 19:32:37 +0000</pubDate>
				<category><![CDATA[networking]]></category>
		<category><![CDATA[system administration]]></category>
		<category><![CDATA[troubleshooting]]></category>
		<category><![CDATA[ebtables]]></category>
		<category><![CDATA[mDNS]]></category>
		<category><![CDATA[multicast]]></category>
		<category><![CDATA[NAT]]></category>
		<category><![CDATA[OpenVPN]]></category>
		<category><![CDATA[tap]]></category>
		<category><![CDATA[tun tap]]></category>
		<category><![CDATA[tuntap]]></category>
		<guid isPermaLink="false">https://blog.vucica.net/?p=5755</guid>

					<description><![CDATA[Trying out the go-chromecast CLI, I was able to see mDNS requests coming to my home network over OpenVPN (a L2 tunnel using a TAP device bridged using br0 on both ends). I could also see responses being generated, but none of them were seen on the other end. The build of dd-wrt I use [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Trying out the <a href="https://github.com/vishen/go-chromecast"><code>go-chromecast</code> CLI</a>, I was able to see mDNS requests coming to my home network over OpenVPN (a L2 tunnel using a TAP device bridged using <code>br0</code> on both ends). I could also see responses being generated, but none of them were seen on the other end. The build of dd-wrt I use has no tcpdump, making it hard to observe both ends of the tunnel.</p>
<p>There’s a lot of sources suggesting a bunch of actions:</p>
<ul>
<li><a href="http://www.tinc-vpn.org/pipermail/tinc/2016-May/004564.html">enable ip_forward</a></li>
<li><a href="http://www.tinc-vpn.org/pipermail/tinc/2016-May/004572.html">disable /sys/devices/virtual/net/$BRIDGE/bridge/multicast_snooping</a></li>
<li><a href="https://blog.michael.kuron-germany.de/2015/07/arp-and-multicast-packets-lost-with-openvpn-in-tap-mode/">disable ageing on the bridge</a></li>
<li>turn off <code>multicast_snooping</code></li>
<li>turn on <code>multicast_snooping</code></li>
<li>turn {off,on} <code>multicast_{router,querier,...}</code>, maybe even use non-{0,1} values (for instance, 2)</li>
<li><a href="https://github.com/kubevirt/kubevirt/issues/2292">tweak <code>group_fwd_mask</code> flags</a> (which is meant for <a href="https://forums.centos.org/viewtopic.php?t=59356">other multicast traffic</a>)</li>
<li>check how many TTL hops do multicast packets have left</li>
<li>figure out IGMP proxying</li>
<li>check IGMP version in use</li>
</ul>
<p>However, that was all tapping in the dark.</p>
<p>But when <a href="http://forums.debian.net/viewtopic.php?f=5&t=111338">someone mentioned ebtables, nat and PREROUTING</a>, this led me to the right path:  what if one of the chains in one of the tables was dropping outgoing packets?</p>
<pre class="syntax">
# ebtables -t nat -L POSTROUTING
Bridge table: nat

Bridge chain: POSTROUTING, entries: 1, policy: ACCEPT
-o tap1 --pkttype-type multicast -j DROP
</pre>
<p>Voila. All multicast packets were being dropped on L2.</p>
<pre class="syntax">
# ebtables -t nat -D POSTROUTING -o tap1 --pkttype-type multicast -j DROP
</pre>
<p>This is fine because I happen to control both ends of the tunnel. Because my systems use multicast only for mDNS, I don’t expect traffic to require drops.</p>
<p>On the bridge device (<code>br0</code> on both ends), I currently have <code>multicast_router</code> set to <code>2</code> on both ends; I have <code>multicast_querier</code> set to <code>1</code> on both ends; non-ddwrt system has <code>multicast_igmp_version</code> set to <code>2</code>; and <code>multicast_snooping</code> is set to <code>1</code> on both ends. I don’t claim correctness of any of these, nor do I claim them to be optimal. But, getting mDNS traffic through is exactly what I wanted, so I’m happy right now.</p>
<div class="plus-one-wrap"><g:plusone href="https://blog.vucica.net/2020/11/ddwrt-router-refusing-to-forward-multicast-packets-over-an-openvpn-tap-device-joined-to-a-bridge.html"></g:plusone></div>]]></content:encoded>
					
					<wfw:commentRss>https://blog.vucica.net/2020/11/ddwrt-router-refusing-to-forward-multicast-packets-over-an-openvpn-tap-device-joined-to-a-bridge.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5755</post-id>	</item>
		<item>
		<title>Exploring the sudoers file: &quot;sudo: sorry, you are not allowed to preserve the environment&quot;</title>
		<link>https://blog.vucica.net/2020/11/exploring-the-sudoers-file-sudo-sorry-you-are-not-allowed-to-preserve-the-environment.html</link>
					<comments>https://blog.vucica.net/2020/11/exploring-the-sudoers-file-sudo-sorry-you-are-not-allowed-to-preserve-the-environment.html#respond</comments>
		
		<dc:creator><![CDATA[Ivan Vučica]]></dc:creator>
		<pubDate>Tue, 10 Nov 2020 13:09:42 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[security]]></category>
		<category><![CDATA[system administration]]></category>
		<category><![CDATA[troubleshooting]]></category>
		<category><![CDATA[unix]]></category>
		<category><![CDATA[environment]]></category>
		<category><![CDATA[ivucica]]></category>
		<category><![CDATA[sudo]]></category>
		<category><![CDATA[sudoers]]></category>
		<category><![CDATA[visudo]]></category>
		<guid isPermaLink="false">https://blog.vucica.net/?p=5738</guid>

					<description><![CDATA[On my NAS I’ve received sudo: sorry, you are not allowed to preserve the environment today when running sudo -E to transfer the environment from whatever the current shell allows sudo to see, into the new shell. That’s because I was copying something from a remote machine to my NAS, and I (temporarily) wanted to [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>On my NAS I’ve received <code>sudo: sorry, you are not allowed to preserve the environment</code> today when running <code>sudo -E</code> to transfer the environment from whatever the current shell allows <code>sudo</code> to see, into the new shell.</p>
<p>That’s because I was copying something from a remote machine to my NAS, and I (temporarily) <a href="https://superuser.com/a/630046/10211">wanted to tell remote <code>rsync</code> to use <code>sudo rsync</code> on my NAS</a> to be sure files will be replicated correctly. While this is <a href="https://unix.stackexchange.com/a/92397/11829">an absolutely horrible idea to do permanently</a>, a temporary workaround in a safe environment is that <code>sudo rsync</code> should not require a root password:</p>
<pre class="syntax">
ivucica ALL=NOPASSWD:/usr/bin/rsync
</pre>
<p>However, compare this to some of the defaults in <code>/etc/sudoers</code>:</p>
<pre class="syntax">
# User privilege specification
root    ALL=(ALL:ALL) ALL

# Allow members of group sudo to execute any command
%sudo   ALL=(ALL:ALL) ALL
</pre>
<p>Without reading the <code>sudoers(5)</code> manpage, I decided to add <code>ALL</code> at the end:</p>
<pre class="syntax">
ivucica ALL=NOPASSWD:/usr/bin/rsync ALL
</pre>
<p>This seemed to work, but despite a lack of a syntax error, it’s wrong (see below): now no password is required for rsync nor for any other command.</p>
<pre class="syntax">
# Wrong order:
#ivucica ALL=NOPASSWD: /usr/bin/rsync, PASSWD: ALL
# Correct order:
ivucica ALL=PASSWD: ALL, NOPASSWD: /usr/bin/rsync
</pre>
<p>The best option, however, is to remove the entry completely given that allowing <code>rsync</code> root without a password is dangerous; even if someone managed to hijack my own account’s non-password NAS credentials, without the password itself they can’t do much.</p>
<hr />
<p>However, looking online for this error, I realized I’ve never looked into the syntax of the <code>sudoers</code> file. What’s <code>Defaults env_reset</code>, for instance? Turns out <code>sudoers(5)</code> is an interesting read. <strong>If you’re seriously going to play with editing /etc/sudoers beyond just adding a user (even just specifying the <code>NOPASSWD</code> tag), please read the manpage and carefully experiment.</strong> Cover all the edge cases you can think of. Have someone else review your changes.</p>
<p>Here’s some interesting stuff:</p>
<ul>
<li><code>#include</code> (and presumably <code>#includedir</code>) directive to include a file can contain <code>%h</code> (a hostname) in file path</li>
<li>to match all users except root, instead of <code>ALL</code> we can specify <code>ALL,!root</code></li>
<li>you can do things like disable setting utmp (<code>set_utmp</code>) or prohibit the capability to disable <code>env_reset</code> (<code>setenv</code>) — which is what I did</li>
<li>the first-time “lecture” status (‘has this user seen the sudo lecture?’) is in <code>/var/lib/sudo/lectured</code> and configurable using <code>lecture_status_dir</code></li>
<li>the password prompt can be overridden with <code>passprompt</code> and can include <code>%H</code> FQDN, <code>%h</code> hostname, <code>%p</code> the user whose password is requested, <code>%U</code> the user whom we’re switching to [caveat: PAM module’s output must match <code>Password:</code> or <code>username's Password:</code></li>
<li>there are ways to specify directives per running host (important for standardized configs deployed across an org), per requesting user, per run-as user, per command</li>
<li>there are tags to tweak execution of a command</li>
</ul>
<hr />
<p>While I haven’t actually tried all of the following, here are some “notes-to-self” on what individual fields mean. <strong>Please prefer learning the details from the manpage.</strong></p>
<p>What does <code>ALL</code> before <code>=</code> mean? Those are the hosts. For instance, we can let <code>roger</code> run anything on all the fileservers:</p>
<pre class="syntax">
Host_Alias FILESERVERS = fs1, fs, fs3
Host_Alias INTERNAL_NETWORK = 192.168.55.0/255.255.255.0
Host_Alias FINANCE = 192.168.75.128/25, 192.168.75.15

roger FILESERVERS = ALL
</pre>
<p>(Just like <code>Host_Alias</code>, there’s <code>User_Alias</code>, <code>Runas_Alias</code> and <code>Cmnd_Alias</code>.)</p>
<p>What’s <code>(ALL:ALL)</code> after <code>=</code>? That’s called a <code>Runas_Spec</code> and it’s saying “You can pretend to be any user of any group.” Let’s only allow <code>roger</code> to run only <code>/usr/bin/rsync</code> and only to do it as <code>mainweb</code>:</p>
<pre class="syntax">
User_Alias     FINANCE_DEPLOY      = james, mike
roger          FILESERVERS         = (mainweb) /usr/bin/rsync
richard        richard-workstation = (www-data) ALL
FINANCE_DEPLOY FINANCE             = (financeweb : financeservices) /usr/bin/rsync
</pre>
<p>And what’s the <code>ALL</code> after <code>(ALL:ALL)</code>? As demonstrated, that’s the command specification.</p>
<p>Alright, so what’s <code>NOPASSWD:</code>? That’s a <code>Tag_Spec</code>. Each command may be prefixed with zero or more tags associated with it, such as <code>EXEC</code>, <code>NOEXEC</code>, <code>PASSWD</code>, <code>NOPASSWD</code>, <code>MAIL</code>, <code>NOMAIL</code>. For instance:</p>
<pre class="syntax">
# Allow ls and cat without password, but require a password for vi.
richard richard-workstation = (www-data) NOPASSWD: /usr/bin/ls, /usr/bin/cat, NOEXEC: PASSWD: /usr/bin/vi
richard richard-workstation = (www-data) NOPASSWD: /usr/bin/ls, /usr/bin/cat, PASSWD: /usr/bin/vi
</pre>
<p>Allowlisting only some commands results in the following when a non-allowed command is run:</p>
<pre class="syntax">
Sorry, user richard is not allowed to execute '/bin/bash' as root on my.machine.hostname.
</pre>
<p>And attempting to run a command from within <code>vi</code> when <code>NOEXEC</code> is specified results in:</p>
<pre class="syntax">
Cannot execute shell /bin/bash
</pre>
<p>There’s even a way to set things like timeouts. But, again, read the manpage for details.</p>
<hr />
<p><sub>As usual, this is not advice; <strong>these are personal notes</strong> from trying to resolve an immediate issue. As this is a security-sensitive feature, for even one person that reads this and configures an important system incorrectly, please note: these notes are written as a hobby. Just like you would with PAM, NSS, LDAP, Kerberos and other things, please carefully read more authoritative documentation sources; I’m not responsible for breakage you may cause with my non-advice.</sub></p>
<div class="plus-one-wrap"><g:plusone href="https://blog.vucica.net/2020/11/exploring-the-sudoers-file-sudo-sorry-you-are-not-allowed-to-preserve-the-environment.html"></g:plusone></div>]]></content:encoded>
					
					<wfw:commentRss>https://blog.vucica.net/2020/11/exploring-the-sudoers-file-sudo-sorry-you-are-not-allowed-to-preserve-the-environment.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5738</post-id>	</item>
		<item>
		<title>Getting all tabs from Chrome on Android</title>
		<link>https://blog.vucica.net/2020/10/getting-all-tabs-from-chrome-on-android.html</link>
					<comments>https://blog.vucica.net/2020/10/getting-all-tabs-from-chrome-on-android.html#respond</comments>
		
		<dc:creator><![CDATA[Ivan Vučica]]></dc:creator>
		<pubDate>Sat, 31 Oct 2020 21:06:24 +0000</pubDate>
				<category><![CDATA[Android]]></category>
		<category><![CDATA[backup]]></category>
		<category><![CDATA[android backup]]></category>
		<category><![CDATA[android chrome tabs]]></category>
		<category><![CDATA[bleed]]></category>
		<category><![CDATA[chrome]]></category>
		<category><![CDATA[chrome backup]]></category>
		<category><![CDATA[chrome backup tabs]]></category>
		<category><![CDATA[chrome tabs]]></category>
		<category><![CDATA[pixel]]></category>
		<category><![CDATA[pixel 3a xl]]></category>
		<category><![CDATA[screen damage]]></category>
		<guid isPermaLink="false">https://blog.vucica.net/?p=5724</guid>

					<description><![CDATA[I damaged the screen on my Pixel 3a XL and it’s now increasingly bleeding meaning hour after hour I see less of the image. See illustration I found online; I still haven’t fully lost the screen, but it’s getting there. Touch still mostly works (except for the top portion of the screen), but enough to [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>I damaged the screen on my Pixel 3a XL and it’s now <a href="https://www.reddit.com/r/GooglePixel/comments/897cip/ugly_purple_color_bleed_out_of_nowhere_for_no/">increasingly bleeding</a> meaning hour after hour I see less of the image. See illustration I found online; I still haven’t fully lost the screen, but it’s getting there. Touch still mostly works (except for the top portion of the screen), but enough to unlock the phone. I’m in Ireland and preliminary price for official repair from Google is EUR167 with tax.</p>
<p><a href="https://github.com/Genymobile/scrcpy">scrcpy</a>, installable from Debian unstable, proved to be useful to connect to the phone. I’ve previously set up developer mode, and I saw enough of the screen to confirm <code>adb</code> connection; now I see and click on the screen on the Linux machine.</p>
<p>One of the things that’s not backed up to the cloud and is terribly bad with syncing is the list of open tabs in Chrome (I’m only seeing about 15 tabs in “Tabs from other devices” on my desktop). There’s no bookmarking of all tabs (<a href="https://bugs.chromium.org/p/chromium/issues/detail?id=488106">crbug/488106</a> and <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=1026222">crbug/1026222</a>).</p>
<p>While Chrome’s developer tools <a href="https://android.stackexchange.com/questions/56635/how-can-i-export-the-list-of-open-chrome-tabs">can be used</a> to connect to the device and see the list of open tabs, <a href="https://dev.to/piczmar_0/when-you-never-close-tabs-on-your-mobile-chrome-browser-2boj">using <code>adb</code> to forward <code>localabstract:chrome_devtools_remote</code></a> is better.</p>
<pre style="syntax bash">
$ adb forward tcp:9222 localabstract:chrome_devtools_remote
</pre>
<p>This way, the relevant API can be accessed over HTTP on port 9222. (You can even visit the service’s home page in your browser.)</p>
<pre style="syntax bash">
$ curl http://localhost:9222/json/list > 2020-10-pixel3axl-chrome-tabs.json
</pre>
<p>You can confirm if the tabs have been fetched using <code>less</code>, or counting the entries in JSON with <code>jq</code>:</p>
<pre style="syntax bash">
$ jq '. | length' 2020-10-pixel3axl-chrome-tabs.json 
396
</pre>
<p>You can also use <code>jq</code> to get just the URLs one at a time:</p>
<pre style="syntax bash">
$ jq  -r '.[].url' 2020-10-pixel3axl-chrome-tabs.json 
</pre>
<p>Unfortunately, the tabs are not ordered correctly. Still, I’d rather have all tabs in wrong order than just a subset in the correct order.</p>
<div class="plus-one-wrap"><g:plusone href="https://blog.vucica.net/2020/10/getting-all-tabs-from-chrome-on-android.html"></g:plusone></div>]]></content:encoded>
					
					<wfw:commentRss>https://blog.vucica.net/2020/10/getting-all-tabs-from-chrome-on-android.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5724</post-id>	</item>
		<item>
		<title>Scanning on Linux from Canon TS5050 over the network</title>
		<link>https://blog.vucica.net/2020/05/scanning-on-linux-from-canon-ts5050-over-the-network.html</link>
					<comments>https://blog.vucica.net/2020/05/scanning-on-linux-from-canon-ts5050-over-the-network.html#respond</comments>
		
		<dc:creator><![CDATA[Ivan Vučica]]></dc:creator>
		<pubDate>Mon, 25 May 2020 17:10:10 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[troubleshooting]]></category>
		<category><![CDATA[canon]]></category>
		<category><![CDATA[network]]></category>
		<category><![CDATA[network scanner]]></category>
		<category><![CDATA[network scanning]]></category>
		<category><![CDATA[scangear]]></category>
		<category><![CDATA[scangear mp]]></category>
		<category><![CDATA[scangearmp]]></category>
		<category><![CDATA[scangearmp2]]></category>
		<category><![CDATA[scanner]]></category>
		<category><![CDATA[scanning]]></category>
		<category><![CDATA[ts5000 series]]></category>
		<category><![CDATA[ts5050]]></category>
		<guid isPermaLink="false">https://blog.vucica.net/?p=5687</guid>

					<description><![CDATA[Turns out that ScanGear MP 3.70 works perfectly with my Canon TS5050.]]></description>
										<content:encoded><![CDATA[<div id="attachment_5690" style="width: 310px" class="wp-caption aligncenter"><a href="https://blog.vucica.net/wp-content/uploads/2020/05/EY4MX1VXgAICz1L.png"><img decoding="async" aria-describedby="caption-attachment-5690" src="https://blog.vucica.net/wp-content/uploads/2020/05/EY4MX1VXgAICz1L-300x137.png" alt="" width="300" height="137" class="size-medium wp-image-5690" srcset="https://blog.vucica.net/wp-content/uploads/2020/05/EY4MX1VXgAICz1L-300x137.png 300w, https://blog.vucica.net/wp-content/uploads/2020/05/EY4MX1VXgAICz1L.png 373w" sizes="(max-width: 300px) 100vw, 300px" /></a><p id="caption-attachment-5690" class="wp-caption-text">scangearmp2 screenshot</p></div>
<p>Turns out that <a href="https://asia.canon/en/support/0100993101/1">ScanGear MP 3.70</a> works perfectly with my Canon TS5050. After unpacking the archive and <code>dpkg -i scangearmp2_3.70-1_amd64.deb</code>, I ran <code>scangearmp2</code>, got simple GTK-based GUI, the TS5050 was recognized, and that was it.</p>
<p><div id="attachment_5692" style="width: 310px" class="wp-caption aligncenter"><a href="https://blog.vucica.net/wp-content/uploads/2020/05/EY4MZq_XYAEWI1r.png"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-5692" src="https://blog.vucica.net/wp-content/uploads/2020/05/EY4MZq_XYAEWI1r-300x213.png" alt="" width="300" height="213" class="size-medium wp-image-5692" srcset="https://blog.vucica.net/wp-content/uploads/2020/05/EY4MZq_XYAEWI1r-300x213.png 300w, https://blog.vucica.net/wp-content/uploads/2020/05/EY4MZq_XYAEWI1r.png 460w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a><p id="caption-attachment-5692" class="wp-caption-text">scangearmp2 screenshot</p></div><br />
I have no idea if it integrates in desktop GUIs, since when I’m under Debian GNU/Linux these days, I am happily using i3 and terminals.</p>
<p>It would be really nice if Canon listed <em>any</em> software for Linux on their <a href="https://www.canon-europe.com/support/consumer_products/products/fax__multifunctionals/inkjet/pixma_ts_series/pixma-ts5050.html?type=software&language=en">official support page for Canon TS5050</a>, but they don’t. There are no Linux “bundles” listed (whew!), but this also means there is no software offered at all. Once you choose Linux, you get random offers for Windows and Mac software — but that’s just generic ads displayed under the ‘no results’ area.</p>
<div class="plus-one-wrap"><g:plusone href="https://blog.vucica.net/2020/05/scanning-on-linux-from-canon-ts5050-over-the-network.html"></g:plusone></div>]]></content:encoded>
					
					<wfw:commentRss>https://blog.vucica.net/2020/05/scanning-on-linux-from-canon-ts5050-over-the-network.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5687</post-id>	</item>
		<item>
		<title>Samba 4 + Windows 10 time synchronization issues</title>
		<link>https://blog.vucica.net/2020/04/5675.html</link>
					<comments>https://blog.vucica.net/2020/04/5675.html#respond</comments>
		
		<dc:creator><![CDATA[Ivan Vučica]]></dc:creator>
		<pubDate>Thu, 23 Apr 2020 20:26:03 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[troubleshooting]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[unix]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[Active Directory]]></category>
		<category><![CDATA[Samba]]></category>
		<category><![CDATA[Samba 4]]></category>
		<category><![CDATA[w32time]]></category>
		<category><![CDATA[w32tm]]></category>
		<guid isPermaLink="false">https://blog.vucica.net/?p=5675</guid>

					<description><![CDATA[Where does ListeningThread -- Recvd 52 of 48/68 bytes come from? If you follow the instructions for setting up Samba 4 AD DC for time synchronization, ntpd (coming out of Debian’s ntp package at some version 4.2.8) should just work.1 I came to this discovery after giving up and discarding my /etc/ntp.conf. Suddenly, after restarting [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><strong>Where does <code>ListeningThread -- Recvd 52 of 48/68 bytes</code> come from?</strong></p>
<p>If you follow <a href="https://wiki.samba.org/index.php/Time_Synchronisation">the instructions for setting up Samba 4 AD DC for time synchronization</a>, <code>ntpd</code> (coming out of Debian’s <code>ntp</code> package at some version 4.2.8) should just work.<sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup></p>
<p>I came to this discovery after giving up and discarding my <code>/etc/ntp.conf</code>. Suddenly, after restarting ntpd and running <code>w32tm /resync</code>, things just worked. It’s not the software that’s broken — it’s me that was crazy.</p>
<p>The packet was now 110 bytes in Wireshark (68 of which was data). This was a stark improvement over seeing a 94 byte packet (52 of which was data). <code>C:\temp\ntpDebug.log</code> <sup id="fnref:2"><a href="#fn:2" rel="footnote">2</a></sup> no longer contained this:</p>
<pre class="syntax">
ListeningThread -- Recvd 52 of 48/68 bytes
</pre>
<p>Hoozah! Now I wanted to figure out what was causing ntpd to send 52b packets, and not either 48b or 68b packets.</p>
<p><strong>Turns out that my <code>restrict</code> statements had unexpected side effects.</strong> For instance, Samba wiki-recommended config tries to unrestrict localhost using <code>restrict 127.0.0.1</code>. <sup id="fnref:3"><a href="#fn:3" rel="footnote">3</a></sup></p>
<p>But I wanted to do the same for IPv6 localhost, so I did <code>restrict ::1</code>. This seems to have greatly confused <code>ntpd</code>.</p>
<p>The way out?</p>
<pre class="syntax">
restrict -4 127.0.0.1
restrict -6 ::1
</pre>
<p>Second mistake was <code>restrict 10.10.10.0 mask 255.255.255.0</code>. It didn’t specify that <code>mssntp</code>  should be enabled. For good measure I threw in <code>-4</code>:</p>
<pre class="syntax">
restrict -4 10.10.10.0 mask 255.255.255.0 mssntp
</pre>
<p>Given that Samba config doesn’t recommend any special allowlisting for my internal IP range, I’ll just remove this line completely; the default restriction from the wiki should cover everything clients need to do anyway:</p>
<pre class="syntax">
# Access control
# Default restriction: Allow clients only to query the time
restrict default kod nomodify notrap nopeer mssntp
</pre>
<p><strong>Moral of the story?</strong> <code>ntpd</code> seems to be awfully sensitive to <code>restrict</code> statements. If w32time service complains or breaks in some way, be sure to remove the statements bit by bit, or make sure IPv4 and IPv6 statements don’t stomp over each other.</p>
<div class="footnotes">
<hr />
<ol>
<li id="fn:1">
Granted, I needed to modify the path to the socket to say  <code>/var/lib/samba/ntp_signd/</code> instead of  <code>/usr/local/samba/var/lib/ntp_signd/</code>, but otherwise it just worked. <a href="#fnref:1" rev="footnote"><img src="https://s.w.org/images/core/emoji/16.0.1/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" /></a>
</li>
<li id="fn:2">
That file was created using <code>w32tm /debug /enable /file:C:\temp\ntpDebug.log /size:102400 /entries:0-300</code> which I found somewhere online. <a href="#fnref:2" rev="footnote"><img src="https://s.w.org/images/core/emoji/16.0.1/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" /></a>
</li>
<li id="fn:3">
Apparently, passing no restrictions at all after the address simply means “unrestrict these peers”. <a href="#fnref:3" rev="footnote"><img src="https://s.w.org/images/core/emoji/16.0.1/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" /></a>
</li>
</ol>
</div>
<div class="plus-one-wrap"><g:plusone href="https://blog.vucica.net/2020/04/5675.html"></g:plusone></div>]]></content:encoded>
					
					<wfw:commentRss>https://blog.vucica.net/2020/04/5675.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5675</post-id>	</item>
		<item>
		<title>Fixing &quot;Use of undefined constant jq_syntax_htmlentities&quot;</title>
		<link>https://blog.vucica.net/2020/01/fixing-use-of-undefined-constant-jq_syntax_htmlentities.html</link>
					<comments>https://blog.vucica.net/2020/01/fixing-use-of-undefined-constant-jq_syntax_htmlentities.html#respond</comments>
		
		<dc:creator><![CDATA[Ivan Vučica]]></dc:creator>
		<pubDate>Sat, 04 Jan 2020 19:26:09 +0000</pubDate>
				<category><![CDATA[troubleshooting]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://blog.vucica.net/?p=5662</guid>

					<description><![CDATA[I upgraded the PHP version backing my WordPress setup to PHP7.3. Of course, something had to go wrong: Warning: Use of undefined constant jq_syntax_htmlentities - assumed 'jq_syntax_htmlentities' (this will throw an Error in a future version of PHP) in ...... wp-content/plugins/jquery-syntax/jquery-syntax.php on line 37 There’s no updates for jquery-syntax plugin that I’m using. Let’s assume [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>I upgraded the PHP version backing my WordPress setup to PHP7.3. Of course, something had to go wrong:</p>
<pre>
Warning: Use of undefined constant jq_syntax_htmlentities - assumed 'jq_syntax_htmlentities' (this will throw an Error in a future version of PHP) in ...... wp-content/plugins/jquery-syntax/jquery-syntax.php on line 37
</pre>
<p>There’s no updates for jquery-syntax plugin that I’m using. Let’s assume that the author will fix this if they ever release an update.</p>
<p>For the time being, opening <code>jquery-syntax.php</code> manually and editing <code>jq_syntax_quote</code> to replace passing what <em>looks like</em> a function object (is it in PHP? I can’t be bothered to check) with a string when invoking <code>preg_replace_callback()</code> does the trick:</p>
<pre class="syntax php">
function jq_syntax_quote($content) {
        $content = preg_replace_callback('/<(pre)(.*?)>(.*?)<\/pre>/imsu','jq_syntax_htmlentities', $content);
        $content = preg_replace_callback('/<(code)(.*?)>(.*?)<\/code>/imsu','jq_syntax_htmlentities', $content);

        return $content;
}
</pre>
<p>Note how <code>jq_syntax_htmlentities</code> received single-quotes around it.</p>
<div class="plus-one-wrap"><g:plusone href="https://blog.vucica.net/2020/01/fixing-use-of-undefined-constant-jq_syntax_htmlentities.html"></g:plusone></div>]]></content:encoded>
					
					<wfw:commentRss>https://blog.vucica.net/2020/01/fixing-use-of-undefined-constant-jq_syntax_htmlentities.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5662</post-id>	</item>
		<item>
		<title>Detecting location of Visual Studio 2017 and 2019</title>
		<link>https://blog.vucica.net/2020/01/detecting-location-of-visual-studio-2017-and-2019.html</link>
					<comments>https://blog.vucica.net/2020/01/detecting-location-of-visual-studio-2017-and-2019.html#respond</comments>
		
		<dc:creator><![CDATA[Ivan Vučica]]></dc:creator>
		<pubDate>Sat, 04 Jan 2020 19:20:39 +0000</pubDate>
				<category><![CDATA[Windows]]></category>
		<category><![CDATA[autodetect]]></category>
		<category><![CDATA[autodetection]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[bazel]]></category>
		<category><![CDATA[detect]]></category>
		<category><![CDATA[detection]]></category>
		<category><![CDATA[microsoft]]></category>
		<category><![CDATA[microsoft visual studio]]></category>
		<category><![CDATA[visual studio 2017]]></category>
		<category><![CDATA[visual studio 2019]]></category>
		<guid isPermaLink="false">https://blog.vucica.net/?p=5656</guid>

					<description><![CDATA[A few years ago, I wanted to use Bazel to build an old project of mine using Visual Studio 2017 Community. Thing is, I don’t install most of MSVS on my system partition, as it’s on a relatively tiny SSD. So, where do I (portably) find it? And how do I set BAZEL_VS (per their [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>A few years ago, I wanted to use Bazel to build an old project of mine using Visual Studio 2017 Community.</p>
<p>Thing is, I don’t install most of MSVS on my system partition, as it’s on a relatively tiny SSD. So, where do I (portably) find it? And how do I set <code>BAZEL_VS</code> (per their documentation) to the correct path?</p>
<p>As I’m much more comfortable writing Bash scripts than writing old DOS-style Batch scripts, and as I’m going to have msys64 (or at least msys32) on my machines, clearly the answer is to write the resulting launcher in Bash. There are downsides to this approach, but it’s doable.</p>
<h2>Do you even need this for Bazel?</h2>
<p><strong>No.</strong> I just tried running <code>bazel-2.0.0-windows-x86_64.exe</code> with my project. It found MSVS2019 out of the box both in <code>cmd.exe</code> and in the MSYS64 shell.</p>
<p>Unfortunately, I have a genrule that depends on bash, which didn’t work in <code>cmd.exe</code> even if I specified <code>BAZEL_SH</code> (missing binary for <code>basename</code>). And when I didn’t pass <code>BAZEL_SH</code> while running under MSYS64, it had trouble finding <code>SDL/SDL.h</code> presumably because the aforementioned genrule didn’t work.</p>
<p><strong>Autodetection of MSVS2019 works</strong>, just set <code>PATH</code> Windows envvar to include msys binaries, and set <code>BAZEL_SH</code> Windows envvar to the output of <code>cygpath -w /usr/bin/bash</code> or <code>cygpath -w /bin/bash</code>.</p>
<p><strong>You may want this for non-Bazel uses.</strong></p>
<h2>Finding Microsoft Visual Studio 2017</h2>
<p>Assuming Bazel 2.0.0 is installed in <code>C:\bazel</code> under the default filename from the release on Github, this does the trick:</p>
<pre class="syntax bash">
#!/bin/bash
# Based on https://superuser.com/a/539680 + searching around registry.
# Finds MSVS2017.
# Slashes when invoking 'reg query' are replaced with dashes because MSYS2.
VSPATH="$(cygpath -u "$(reg query 'HKLM\SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7' -v 15.0 | tail -n+3 | head -n1  | awk '{for (i=3;i<=NF;i++) {printf "%s ",$i;};}' | sed 's/ *$//')")"

export BAZEL_SH="$(cygpath -w /usr/bin/bash)"
export BAZEL_VS="$VSPATH"

/c/bazel/bazel-2.0.0-windows-x86_64.exe $@
</pre>
<h2>Finding Microsoft Visual Studio 2019</h2>
<p>Unfortunately this is broken as of MSVS2019. See the <a href="https://developercommunity.visualstudio.com/content/problem/438521/no-registry-entry-160-in-hklmsoftwarewow6432nodemi.html">explanation why that registry key is not used anymore</a>.</p>
<p>The new situation is better: there’s a tool that <em>does</em> get installed in a well-known path: <code>%ProgramFiles(x86)%/Microsoft Visual Studio/Installer/vswhere.exe</code>.</p>
<p>The problem is merely that Bash doesn’t like parentheses in environment variable names, so <code>${ProgramFiles(x86)}</code> won’t be acceptable. However, it was visible in <code>env</code> output! <a href="http://mingw-users.1079350.n2.nabble.com/msysGit-bash-and-PROGRAMFILES-X86-environment-variable-on-Win64-td3920518.html">Other people have spotted the same thing</a>, but as their writings talk about <code>PROGRAMFILES(X86)</code> in all caps, I’ve concluded that maybe it’s better to add the <code>I</code> flag to their sed-based solution.</p>
<pre class="syntax bash">
#!/bin/bash
# Let's use VSWhere:
PROGRAMFILES_X86=$(env | sed -n s,'^PROGRAMFILES(X86)=',,pI) # because parens are not valid envvar names: http://mingw-users.1079350.n2.nabble.com/msysGit-bash-and-PROGRA$
VSWHERE=${PROGRAMFILES_X86}/Microsoft\ Visual\ Studio/Installer/vswhere.exe
VSWHERE="$(cygpath -u "${VSWHERE}")"

# Finding VC: https://github.com/microsoft/vswhere/wiki/Find-VC
VSPATH=$("${VSWHERE}" -latest -products '*' -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -property installationPath)

export BAZEL_SH="$(cygpath -w /usr/bin/bash)"
export BAZEL_VS="$VSPATH"

/c/bazel/bazel-2.0.0-windows-x86_64.exe $@
</pre>
<h2>VSCode</h2>
<p>The problem with using Bazel integration into VSCode is that it wants a path to Bazel. But Bazel wants to have <code>BAZEL_VS</code> set.</p>
<p>Maybe I could work around this by writing a tool in a compilable language, then have it pass on all CLI arguments to actual <code>bazel.exe</code>, while also setting <code>BAZEL_VS</code>. Or maybe Bazel supports some settings in <code>.bazelrc</code>. I didn’t care to check. Instead, I’ve <a href="https://stackoverflow.com/a/46838044/39974">used <code>msys2_shell.cmd</code></a> as the ‘shell’ for the integrated VSCode terminal. I’m used to manually running Bazel and I don’t care enough about interactive debugging. For now, I just don’t care enough to properly integrate Bazel into VSCode on Windows (though it would be neat).</p>
<h2>Why even bother with Windows?</h2>
<p>I need to trivially compare networking traffic between my project and a third-party program. The third-party program is written for Windows; it would likely work on other platforms under Wine, but I don’t care enough to explore whether I can make a third-party binary patcher for that program work under Wine.</p>
<p>My program still works on Linux, built whether with Bazel or using Makefiles; but the deprecated SDL 1.2 was recently broken on macOS, my program won’t work on macOS.</p>
<p>Getting this to work is also a nice exercise.</p>
<div class="plus-one-wrap"><g:plusone href="https://blog.vucica.net/2020/01/detecting-location-of-visual-studio-2017-and-2019.html"></g:plusone></div>]]></content:encoded>
					
					<wfw:commentRss>https://blog.vucica.net/2020/01/detecting-location-of-visual-studio-2017-and-2019.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5656</post-id>	</item>
		<item>
		<title>Anno 1404 crashing when clicking on Quickstart</title>
		<link>https://blog.vucica.net/2019/08/anno-1404-crashing-when-clicking-on-quickstart.html</link>
					<comments>https://blog.vucica.net/2019/08/anno-1404-crashing-when-clicking-on-quickstart.html#respond</comments>
		
		<dc:creator><![CDATA[Ivan Vučica]]></dc:creator>
		<pubDate>Sat, 17 Aug 2019 12:55:51 +0000</pubDate>
				<category><![CDATA[troubleshooting]]></category>
		<category><![CDATA[Anno 1404]]></category>
		<category><![CDATA[games]]></category>
		<category><![CDATA[Windows 10]]></category>
		<guid isPermaLink="false">https://blog.vucica.net/?p=5641</guid>

					<description><![CDATA[I finally found the solution to the issue on the GOG.com forums. Nothing obvious like setting admin privileges helped. No, it’s more insidious. Apparently when you go to regional settings, both the “Country or Region” and the “Regional Format” values must match the country. I’ve had these set to “Ireland” + “English (Europe)”. Before this, [&#8230;]]]></description>
										<content:encoded><![CDATA[<div id="attachment_5648" style="width: 310px" class="wp-caption aligncenter"><a href="https://blog.vucica.net/wp-content/uploads/2019/08/Annotation-2019-08-17-135302.png"><img loading="lazy" decoding="async" aria-describedby="caption-attachment-5648" src="https://blog.vucica.net/wp-content/uploads/2019/08/Annotation-2019-08-17-135302-300x162.png" alt="Regional Settings on Windows 10" width="300" height="162" class="size-medium wp-image-5648" srcset="https://blog.vucica.net/wp-content/uploads/2019/08/Annotation-2019-08-17-135302-300x162.png 300w, https://blog.vucica.net/wp-content/uploads/2019/08/Annotation-2019-08-17-135302-768x415.png 768w, https://blog.vucica.net/wp-content/uploads/2019/08/Annotation-2019-08-17-135302-1024x553.png 1024w, https://blog.vucica.net/wp-content/uploads/2019/08/Annotation-2019-08-17-135302-624x337.png 624w, https://blog.vucica.net/wp-content/uploads/2019/08/Annotation-2019-08-17-135302.png 1259w" sizes="auto, (max-width: 300px) 100vw, 300px" /></a><p id="caption-attachment-5648" class="wp-caption-text">Regional Settings on Windows 10. Making the countries match fixes Anno 1404.</p></div>
<p>I finally found the solution to the issue <a href="https://www.gog.com/forum/anno_series/anno_1404_crashing/post11">on the GOG.com forums</a>. Nothing obvious like setting admin privileges helped.</p>
<p>No, it’s more insidious.</p>
<p>Apparently when you go to regional settings, both the “Country or Region” and the “Regional Format” values must match the country.</p>
<p>I’ve had these set to “Ireland” + “English (Europe)”. Before this, I likely had it set to “Ireland” + “Croatian (Croatia)”.</p>
<p>Changing the values to “Ireland” + “English (Ireland)” resolved the issue.</p>
<p>I can finally play the game years after buying it. This was done on Windows 10 1903 (build 18362.10012).</p>
<div class="plus-one-wrap"><g:plusone href="https://blog.vucica.net/2019/08/anno-1404-crashing-when-clicking-on-quickstart.html"></g:plusone></div>]]></content:encoded>
					
					<wfw:commentRss>https://blog.vucica.net/2019/08/anno-1404-crashing-when-clicking-on-quickstart.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5641</post-id>	</item>
		<item>
		<title>Time for FOSDEM 2019</title>
		<link>https://blog.vucica.net/2019/01/time-for-fosdem-2019.html</link>
					<comments>https://blog.vucica.net/2019/01/time-for-fosdem-2019.html#respond</comments>
		
		<dc:creator><![CDATA[Ivan Vučica]]></dc:creator>
		<pubDate>Mon, 28 Jan 2019 18:19:54 +0000</pubDate>
				<category><![CDATA[communications]]></category>
		<category><![CDATA[travel]]></category>
		<category><![CDATA[activitypub]]></category>
		<category><![CDATA[fediverse]]></category>
		<category><![CDATA[FOSDEM]]></category>
		<category><![CDATA[FOSDEM 2019]]></category>
		<category><![CDATA[FOSDEM19]]></category>
		<category><![CDATA[ostatus]]></category>
		<guid isPermaLink="false">https://blog.vucica.net/?p=5616</guid>

					<description><![CDATA[Previously I thought I would not head to Brussels this year, but it turned out I will. Let me know if you’d like to meet. I’m not sure if I’ll go to the beer event. This year I hope to meet up with people interested in fediverse-related interop. Here’s a meetup thread. I’ve also created [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Previously I thought I would not head to Brussels this year, but it turned out I will. Let me know if you’d like to meet. I’m not sure if I’ll go to the beer event.</p>
<p>This year I hope to meet up with people interested in fediverse-related interop. Here’s <a href="https://vucica.net/notice/358858">a meetup thread</a>.</p>
<p>I’ve also created an XMPP chatroom for meeting fediverse folks, in case realtime chat is needed; see <a href="xmpp:fediverse@muc.badc0de.net?join">xmpp:fediverse@muc.badc0de.net?join</a><sup id="fnref:1"><a href="#fn:1" rel="footnote">1</a></sup>. There’s a small web UI at <a href="https://badc0de.net/fosdem/2019/fediverse/">https://badc0de.net/fosdem/2019/fediverse/</a><sup id="fnref:4"><a href="#fn:4" rel="footnote">2</a></sup> and an IRC frontend<sup id="fnref:2"><a href="#fn:2" rel="footnote">3</a></sup> at <a href="irc://irc.badc0de.net:6667/#fediverse">irc://irc.badc0de.net:6667/#fediverse</a>; please join <code>#fediverse</code> manually. No guarantees about reliability of the XMPP server, of the HTTP proxy<sup id="fnref:3"><a href="#fn:3" rel="footnote">4</a></sup>, of the web UI, or of the IRC frontend. <img src="https://s.w.org/images/core/emoji/16.0.1/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p>On a related note, it’s disappointing that there’s a social fragmentation between Matrix, fediverse and XMPP, but eh. It would have been nice if ActivityPub was (like OStatus protocol suite before it) based around XML and Atom; it would have made pushing for supplanting the under-utilized XEP-0277 and its <code>urn:xmpp:microblogging:0</code> with something that had a model of favoriting and commenting similar to fediverse.</p>
<p>Alas, to be useful now would probably require imagining ActivityPub 2.0’s model and vocabulary over XML, and use Atom for posts and activities. <em>shrug</em></p>
<div class="footnotes">
<hr />
<ol>
<li id="fn:1">
This is running <a href="https://prosody.im">Prosody</a>. <a href="#fnref:1" rev="footnote"><img src="https://s.w.org/images/core/emoji/16.0.1/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" /></a>
</li>
<li id="fn:4">
This is using <a href="https://conversejs.org">Converse.js</a>. <a href="#fnref:4" rev="footnote"><img src="https://s.w.org/images/core/emoji/16.0.1/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" /></a>
</li>
<li id="fn:2">
This is running the ultra-tiny <a href="https://github.com/midar/muc2irc">MUC2IRC</a>, written in Objective-C using <a href="https://github.com/ObjFW/ObjFW">ObjFW</a>. <a href="#fnref:2" rev="footnote"><img src="https://s.w.org/images/core/emoji/16.0.1/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" /></a>
</li>
<li id="fn:3">
This is the <a href="https://github.com/twonds/punjab">Punjab</a> BOSH connection manager running behind Haproxy running behind nginx running in a Mesos cluster managed by Marathon. <img src="https://s.w.org/images/core/emoji/16.0.1/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /> <a href="#fnref:3" rev="footnote"><img src="https://s.w.org/images/core/emoji/16.0.1/72x72/21a9.png" alt="↩" class="wp-smiley" style="height: 1em; max-height: 1em;" /></a>
</li>
</ol>
</div>
<div class="plus-one-wrap"><g:plusone href="https://blog.vucica.net/2019/01/time-for-fosdem-2019.html"></g:plusone></div>]]></content:encoded>
					
					<wfw:commentRss>https://blog.vucica.net/2019/01/time-for-fosdem-2019.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5616</post-id>	</item>
		<item>
		<title>Using PostgreSQL row commit IDs and live stats</title>
		<link>https://blog.vucica.net/2018/11/using-postgresql-row-commit-ids-and-live-stats.html</link>
					<comments>https://blog.vucica.net/2018/11/using-postgresql-row-commit-ids-and-live-stats.html#respond</comments>
		
		<dc:creator><![CDATA[Ivan Vučica]]></dc:creator>
		<pubDate>Fri, 09 Nov 2018 00:01:51 +0000</pubDate>
				<category><![CDATA[databases]]></category>
		<category><![CDATA[PostgreSQL]]></category>
		<category><![CDATA[sql]]></category>
		<guid isPermaLink="false">https://blog.vucica.net/?p=5587</guid>

					<description><![CDATA[Once again, it’s time to write down some notes for personal use. Let me know if what I’m jotting down here is particularly wrong. PostgreSQL can tell you what are the commit IDs that touched a particular table. You query the system column named xmin. prosody=> select xmin from prosody limit 5; xmin -------- 212236 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Once again, it’s time to write down some notes for personal use. Let me know if what I’m jotting down here is particularly wrong.</p>
<p>PostgreSQL can tell you what are the commit IDs that touched a particular table. You query the <a href="https://www.postgresql.org/docs/9.1/ddl-system-columns.html">system column</a> named <code>xmin</code>.</p>
<pre class="syntax">
prosody=> select xmin from prosody limit 5;
  xmin
--------
 212236
 770460
 770460
 967052
   1493
(5 rows)
</pre>
<p>You can also ask for the timestamp when this commit was created; however, that requires you to start tracking timestamps for each commit ID.</p>
<pre class="syntax">
prosody=> select pg_xact_commit_timestamp(xmin), * from prosody;

ERROR:  could not get commit timestamp data
HINT:  Make sure the configuration parameter "track_commit_timestamp" is set.

</pre>
<p>This seems to be rather useful for built-in tracking of the modification timestamp and for etags. If the database backend is well structured, it may be possible to structure queries in such a way to quickly check when the results were last modified, and help the web frontend avoid serving and requesting the results. I don’t have a clear way to do it yet, but while I don’t think impact on the database will be significant, it may help shave off some serving bytes or requests to other backends.</p>
<p>Commit IDs also roll over after 32bit, so their use on a high traffic site needs to be closely considered. Then again, by the time you have over four billion writes, your caches will probably otherwise expire anyway.</p>
<p>Table <code>pg_stat_activity</code> is interesting and lets you see the transactions and even queries in flight. This’ll be slightly messy, but click ‘view raw code’ to see the original formatting, and scroll around a bit.</p>
<pre class="syntax">
$ sudo -u postgres psql
psql (10.1, server 9.6.10)
Type "help" for help.

postgres=# SELECT pid, query FROM pg_stat_activity;
 pid  |                                                                                                                                                                                                              query                                                                                                                                                            
------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 8968 | SELECT o0."id", o0."token", o0."refresh_token", o0."valid_until", o0."user_id", o0."app_id", o0."inserted_at", o0."updated_at" FROM "oauth_tokens" AS o0 WHERE (o0."token" = $1)
...
...
 9869 | SELECT pid, query FROM pg_stat_activity;
(12 rows)
postgres=# SELECT * FROM pg_stat_activity;
 datid  |   datname   | pid  | usesysid | usename  | application_name | client_addr | client_hostname | client_port |         backend_start         |          xact_start           |          query_start          |         state_change          | wait_event_type | wait_event |        state        | backend_xid | backend_xmin |                                                                                                                                                                                                              query                       
--------+-------------+------+----------+----------+------------------+-------------+-----------------+-------------+-------------------------------+-------------------------------+-------------------------------+-------------------------------+-----------------+------------+---------------------+-------------+--------------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 146762 | yyyyyyy_dev | 8968 |   146761 | yyyyyyy |                  | 127.0.0.1   |                 |       47545 | 2018-11-08 23:44:52.761448+00 |                               | 2018-11-08 23:50:33.742608+00 | 2018-11-08 23:50:40.75014+00  |                 |            | idle                |             |              | SELECT u0."id", u0."bio", u0."email", u0."name", u0."nickname", u0."password_hash", u0."following", u0."ap_id", u0."avatar", u0."local", u0."info", u0."follower_address", u0."last_refreshed_at", u0."inserted_at", u0."updated_at" FROM "users" AS u0 WHERE (u0."id" = $1)
....
  16391 | prosody     | 8833 |    16386 | prosody  |                  | 10.0.AA.AAA |                 |       51490 | 2018-11-08 23:44:30.819644+00 | 2018-11-08 23:50:28.826344+00 | 2018-11-08 23:50:28.826344+00 | 2018-11-08 23:50:28.826362+00 |                 |            | idle in transaction |             |              | BEGIN
  12409 | postgres    | 9869 |       10 | postgres | psql             |             |                 |          -1 | 2018-11-08 23:48:29.262371+00 | 2018-11-08 23:50:41.487958+00 | 2018-11-08 23:50:41.487958+00 | 2018-11-08 23:50:41.487961+00 |                 |            | active              |             |      1606549 | SELECT * FROM pg_stat_activity;
(12 rows)

</pre>
<div class="plus-one-wrap"><g:plusone href="https://blog.vucica.net/2018/11/using-postgresql-row-commit-ids-and-live-stats.html"></g:plusone></div>]]></content:encoded>
					
					<wfw:commentRss>https://blog.vucica.net/2018/11/using-postgresql-row-commit-ids-and-live-stats.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5587</post-id>	</item>
		<item>
		<title>Now posting photography on Instagram</title>
		<link>https://blog.vucica.net/2018/11/now-posting-photography-on-instagram.html</link>
					<comments>https://blog.vucica.net/2018/11/now-posting-photography-on-instagram.html#respond</comments>
		
		<dc:creator><![CDATA[Ivan Vučica]]></dc:creator>
		<pubDate>Sat, 03 Nov 2018 01:35:43 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://blog.vucica.net/?p=5579</guid>

					<description><![CDATA[I’m now available on Instagram. A while ago I became available on fediverse (Mastodon, Pleroma, …) on the same address as usual: myname@mylastname.net (substitute as necessary).]]></description>
										<content:encoded><![CDATA[<p>I’m now available on <a href="https://instagram.com/ivucica.photography">Instagram</a>.</p>
<p>A while ago I became available on fediverse (Mastodon, Pleroma, …) on the same address as usual: <code>myname@mylastname.net</code> (substitute as necessary).</p>
<div class="plus-one-wrap"><g:plusone href="https://blog.vucica.net/2018/11/now-posting-photography-on-instagram.html"></g:plusone></div>]]></content:encoded>
					
					<wfw:commentRss>https://blog.vucica.net/2018/11/now-posting-photography-on-instagram.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5579</post-id>	</item>
		<item>
		<title>On Mastodon and the &quot;fediverse&quot;</title>
		<link>https://blog.vucica.net/2018/08/on-mastodon-and-the-fediverse.html</link>
					<comments>https://blog.vucica.net/2018/08/on-mastodon-and-the-fediverse.html#respond</comments>
		
		<dc:creator><![CDATA[Ivan Vučica]]></dc:creator>
		<pubDate>Mon, 20 Aug 2018 19:01:09 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<guid isPermaLink="false">https://blog.vucica.net/2018/08/on-mastodon-and-the-fediverse.html</guid>

					<description><![CDATA[I do like the freedom from lock-in. That’s why I run my own federated XMPP server (though a domain whitelist applies due to spam – contact me if you want to interop). I do want to regain control over my social postings. I don’t use Facebook; I’m mainly on Twitter. I don’t mind Twitter as [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>I do like the freedom from lock-in. That’s why I run my own federated XMPP server (though a domain whitelist applies due to spam – contact me if you want to interop).</p>
<p>I do want to regain control over my social postings. I don’t use Facebook; I’m mainly on Twitter. I don’t mind Twitter as much, but it would be nice to host my own posts.</p>
<p>That’s why I will not be signing up for a Mastodon instance. Allegedly migration to another instance is easy. But permalinks to posts would still be stored on a domain owned by someone else. Thank you – but then I might as well stay on Twitter.</p>
<p>What about running my own? I have a test deployment I can spin up, but I don’t want to pay for the resources that would be required to make it a permanent thing. Mastodon’s minimum requirements are huge.</p>
<p>Why not GNU Social? I am trying to reduce my consumption of PHP.</p>
<p>Why not Pleroma? Maybe I’ll do that. I need to check it out, however, I’m not well versed in Erlang and fediverse stuff seems like something I may want to customize.</p>
<p>Customize in what way? Bridging to XMPPs microblogging seems like an interesting possibility. And sharing more than just “notes” (Twitter’s tweets, Mastodon’s toots) seems like a good way of weaning myself off of WordPress. ActivityStreams vocabulary (which makes an appearance in OStatus and is basis for ActivityPub) has more than just Notes.</p>
<div class="plus-one-wrap"><g:plusone href="https://blog.vucica.net/2018/08/on-mastodon-and-the-fediverse.html"></g:plusone></div>]]></content:encoded>
					
					<wfw:commentRss>https://blog.vucica.net/2018/08/on-mastodon-and-the-fediverse.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5574</post-id>	</item>
		<item>
		<title>Enabling zoom &#039;key&#039; and spell key on Microsoft Natural® Ergonomic Keyboard 4000</title>
		<link>https://blog.vucica.net/2018/07/enabling-zoom-key-and-spell-key-on-microsoft-natural-ergonomic-keyboard-4000.html</link>
					<comments>https://blog.vucica.net/2018/07/enabling-zoom-key-and-spell-key-on-microsoft-natural-ergonomic-keyboard-4000.html#respond</comments>
		
		<dc:creator><![CDATA[Ivan Vučica]]></dc:creator>
		<pubDate>Fri, 06 Jul 2018 16:15:53 +0000</pubDate>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[troubleshooting]]></category>
		<category><![CDATA[unix]]></category>
		<category><![CDATA[evdev]]></category>
		<category><![CDATA[input]]></category>
		<category><![CDATA[keyboard]]></category>
		<category><![CDATA[libinput]]></category>
		<category><![CDATA[Microsoft Natural® Ergonomic Keyboard 4000]]></category>
		<category><![CDATA[udev]]></category>
		<guid isPermaLink="false">https://blog.vucica.net/?p=5563</guid>

					<description><![CDATA[The procedure is not best described elsewhere on the web. This article is a mess, too, but it works for me. Keys need to be remapped to something under keycode 256 in order to work under X11. Try using evtest and pressing keys to see what the keys map to right now. evtest can will [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>The procedure is not best described elsewhere on the web. This article is a mess, too, but it works for me.</p>
<p>Keys need to be remapped to something under keycode 256 in order to work under X11.</p>
<ul>
<li>Try using <code>evtest</code> and pressing keys to see what the keys map to right now.
<ul>
<li><code>evtest</code> can will also tell you what are <em>all</em> the events supported by the device.</li>
<li><code>evtest</code> will show two devices; you are interested in the second one (which exposes all the extended keys, such as <code>new</code>, <code>reply</code>, <code>open</code>, <code>send</code>, etc.</li>
</ul>
</li>
<li>Use <code>xev</code> to see whether the keys are recognized, and as what are they recognized, in X11.</li>
</ul>
<p>Now for the juicy part:</p>
<pre class="syntax conf">
# put this into: /etc/udev/hwdb.d/61-keyboard-custom.hwdb

# then to update:
#  sudo udevadm hwdb --update && sudo udevadm control --reload-rules && sudo udevadm control --reload
# and:
#  sudo udevadm trigger
# or:
#  for i in /sys/class/input/* ; do if [[ -e "$i"/id/vendor ]] && [[ -e "$i"/id/product ]] && [[ "$(cat "$i"/id/vendor)" == 045e ]] && [[ "$(cat "$i"/id/product)" == 00db ]] ;  then echo $i ; echo change | sudo tee $i/uevent ; fi ; done

# Natural Keyboard 4000
# formerly:
#keyboard:usb:v045Ep00DB*
# now:
evdev:input:b0003v045Ep00DB*
 KEYBOARD_KEY_0c01ab=finance             # KEY_SPELLCHECK    to KEY_FINANCE
 KEYBOARD_KEY_c022d=up
 KEYBOARD_KEY_c022e=down
</pre>
<p>We’re naming it <code>61-keyboard-custom.hwdb</code> in order to have it come after <code>/lib/udev/hwdb.d/60-keyboard.hwdb</code>.</p>
<p>Instead of <code>finance</code>, <code>up</code> and <code>down</code> keys, try taking something from this list: <a href="https://hal.freedesktop.org/quirk/quirk-keymap-list.txt">quirk-keymap-list.txt</a> — however, I am not certain how to determine which ones are under 256 except by looking at <code>evtest</code>‘s output.</p>
<p>You can map to keycode 255 and use <code>xmodmap -e "keycode 255 = XF86ZoomIn"</code> to map to a ‘proper’ zoom in key.</p>
<p>On a related note: If you want to remap scancodes to keycodes, you can do it on the fly using <a href="https://www.systutorials.com/docs/linux/man/8-setkeycodes/">setkeycodes(8)</a></p>
<p>Some sources:</p>
<ul>
<li><a href="http://marcin.juszkiewicz.com.pl/2014/03/03/how-to-get-zoom-slider-on-microsoft-keyboard-recognized-by-x11/">http://marcin.juszkiewicz.com.pl/2014/03/03/how-to-get-zoom-slider-on-microsoft-keyboard-recognized-by-x11/</a></li>
<li><a href="https://unix.stackexchange.com/q/39370">https://unix.stackexchange.com/q/39370</a></li>
</ul>
<hr />
<p>EDIT 2021-01-27:</p>
<ul>
<li>Another useful resource is <a href="https://wiki.archlinux.org/title/map_scancodes_to_keycodes">Arch Linux wiki’s article on mapping the scancodes</a>.</li>
<li>Config files mapping from scancodes to X keycodes can be found in <code>/usr/share/X11/xkb/keycodes</code>. For instance, scancodes generated by evdev are in the file <code>evdev</code> in that directory.</li>
<li>Scancodes can be found using <code>showkey</code> — which only works from the virtual console, not from within X11.</li>
</ul>
<div class="plus-one-wrap"><g:plusone href="https://blog.vucica.net/2018/07/enabling-zoom-key-and-spell-key-on-microsoft-natural-ergonomic-keyboard-4000.html"></g:plusone></div>]]></content:encoded>
					
					<wfw:commentRss>https://blog.vucica.net/2018/07/enabling-zoom-key-and-spell-key-on-microsoft-natural-ergonomic-keyboard-4000.html/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">5563</post-id>	</item>
	</channel>
</rss>
