<rss version="2.0">
	<channel>
		<title>lunacb's funky site</title>
		<link>https://lunacb.house/blog</link>
		<description>blog at lunacb.house</description>
<item>
	<title>Ruby being a good language</title>
	<link>https://lunacb.house/2022-11-05.html</link>
	<pubDate>2022-11-05 15:21:04 EDT</pubDate>
	<description>
		&lt;p class=&quot;snx-paragraph&quot;&gt;
Today I had a sudden burst of motivation to do some code-golfing on my
local filesystem in Ruby. I&amp;apos;m a bit rusty but I picked it up again pretty
quickly. Ruby has a rich set of features designed for iterating over Things in
general, and a standard library to support it (a). I don&amp;apos;t know how much of my
enjoyment of this is a lack of functional programming knowledge, but the tools
provided by Ruby are expressive enough to make small but complex operations on
Lists of Things effortless to write and read, sometimes to the extent of
written in it code being self-documenting in places where they wouldn&amp;apos;t be in
other languages.
&lt;/p&gt;
&lt;p class=&quot;snx-path-p&quot;&gt;&lt;a class=&quot;snx-path-a&quot; href=&quot;https://ruby-doc.org/core-3.1.2/Enumerable.html&quot;&gt;
(a) Enumerable class in Ruby
&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
I maintain a daily log of progress on projects that I&amp;apos;m working on,
including the amount of time spent on them each day, just for fun. The program
I wrote in Ruby prints the total time spent on a project by reading the daily
time logged in each diary entry for that project. Here&amp;apos;s the program:
&lt;/p&gt;
&lt;pre class=&quot;snx-code&quot;&gt;
#!/usr/bin/env ruby

where = &amp;quot;/home/luna/docs/studywiki/diary/&amp;quot;
project = /= PROJECT: chess/
h=0
m=0

Dir.children(where).select { |p| not File.directory?(where+p) and File.open(where+p).any? { |f| f.each_line.any? { |line| line =~ project } } }.each do |p|
  File.open(where+p) { |f| f.each_line { |s| if s =~ /^TIME:s*([0-9]+)hs*([0-9]+)m/ then h += $1.to_i; m += $2.to_i end } }
end
puts &amp;quot;#{h+(m/60).to_i}h #{m%60}m&amp;quot;
&lt;/pre&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
as long as you can actually read Ruby, this program reads out very
similarly to a description of it in plain English; Take the
&lt;b class=&quot;snx-text-bold&quot;&gt;
children
&lt;/b&gt;
of
the directory,
&lt;b class=&quot;snx-text-bold&quot;&gt;
select
&lt;/b&gt;
only the ones which are
&lt;b class=&quot;snx-text-bold&quot;&gt;
not
&lt;/b&gt;
&lt;b class=&quot;snx-text-bold&quot;&gt;
directories
&lt;/b&gt;
&lt;b class=&quot;snx-text-bold&quot;&gt;
and
&lt;/b&gt;
that, when
&lt;b class=&quot;snx-text-bold&quot;&gt;
opened,
&lt;/b&gt;
contain
&lt;b class=&quot;snx-text-bold&quot;&gt;
any
&lt;/b&gt;
&lt;b class=&quot;snx-text-bold&quot;&gt;
lines
&lt;/b&gt;
matching the
&lt;b class=&quot;snx-text-bold&quot;&gt;
project
&lt;/b&gt;
header. With
&lt;b class=&quot;snx-text-bold&quot;&gt;
each
&lt;/b&gt;
of these selected files,
&lt;b class=&quot;snx-text-bold&quot;&gt;
open
&lt;/b&gt;
them
and test
&lt;b class=&quot;snx-text-bold&quot;&gt;
each line
&lt;/b&gt;
against the TIME: pattern, and if matching, increment
the hour and minute counter accordingly.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
It just flows. Wheee!!
&lt;/p&gt;

	</description>
</item>
<item>
	<title>Sysadmin witch studytime</title>
	<link>https://lunacb.house/2022-10-23.html</link>
	<pubDate>2022-10-23 17:17:00 EDT</pubDate>
	<description>
		&lt;p class=&quot;snx-paragraph&quot;&gt;
Wow, it&amp;apos;s been a hot minute since I touched the blog. I do enjoy writing
though, when I have the motivation and the inspiration, so I might try to do
more often. Since I&amp;apos;ve been gone, I&amp;apos;ve been writing some small servers. One&amp;apos;s
completed so far, and another&amp;apos;s going to enter into final stages of development
not too far in the future. All of this is helping me to learn how servers work
by writing them, as well as how to use the administration tools needed to run
them, which makes for an adventurous time. I&amp;apos;m also in the beginning stages of
educating myself about the Cloud specifically, mostly because it makes me more
hireable at $BIG_COMPANY. not that I like $BIG_COMPANY though, he&amp;apos;s kinda
smelly and gross. I&amp;apos;d much prefer to work somewhere less evil, but this is work
I can do that I won&amp;apos;t actually hate, I guess. I have begun to enjoy working
with Cloud software though, despite the massive amount of complexity
introduced by the architectural pattern. A boring, normal server is what I
started with though, which was nice and cozy to develop.
&lt;/p&gt;
&lt;h2 class=&quot;snx-heading&quot;&gt;
A Chess Server
&lt;/h2&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
I started off with a server to play Chess on, which seemed simple enough
for a first project. It took a month to complete, which is a bit longer than I
expected, but I think it&amp;apos;s a fairly decent piece of software, although
lacking in polish. So, now you can play SSHCHESS, either here on this server or
over on tilde.town with
&lt;code class=&quot;snx-text-code&quot;&gt;
town chess
&lt;/code&gt;
if you have an account there (a) (b).
I offloaded the actual network interconnectivity problem to ssh or your
favorite remote shell program, so all I had to deal with was a Unix domain
socket, which is a lot more reliable and easy to handle.
&lt;/p&gt;
&lt;p class=&quot;snx-path-p&quot;&gt;&lt;a class=&quot;snx-path-a&quot; href=&quot;ssh://chess@lunacb.house&quot;&gt;
(a) ssh
&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;snx-path-p&quot;&gt;&lt;a class=&quot;snx-path-a&quot; href=&quot;https://tilde.town&quot;&gt;
(b) tilde.town
&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
I wrote the software in Go, which means I first had to learn Go. Some the
language is decent, but it has some annoying parts too. The syntax,
specifically, was something the Go devs don&amp;apos;t seem to be good at, in my
experience. One instance of this odd behavior that I feel like ranting about is
semicolons. Go automatically inserts them into your code JavaScript-style, as a
sort of preprocessor step. This is already the worst way to deal with your
hatred of semicolons (a fair thing to dislike, though), and it&amp;apos;s worse because
Go&amp;apos;s rules for deciding where they should be inserted are horribly dumb (c). If
you want to spread something like an if statement out over multiple lines, you
may or may not see a cryptic error spit out by your compiler about unexpected
semicolons somewhere in your code that doesn&amp;apos;t actually exist in the file.
maybe the Go devs all have editor displays with 300-character widths, and the
problem never crossed their minds. There&amp;apos;s plenty of other awkward things I
don&amp;apos;t like as well, like the ways in which Go enforces naming and code
organization.
&lt;/p&gt;
&lt;p class=&quot;snx-path-p&quot;&gt;&lt;a class=&quot;snx-path-a&quot; href=&quot;https://go.dev/doc/effective_go#semicolons&quot;&gt;
(c) Go semicolons
&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
This isn&amp;apos;t me saying that go is an Evil language, though. Most of it
isn&amp;apos;t that bad. Concurrency is pretty good. I&amp;apos;d never really worked with
threads before, so my opinion doesn&amp;apos;t count for too much, but they were
surprisingly friendly to start out with in Go. Most of my programming life I&amp;apos;d
been scared of threads, which seemed buggy and rude and didn&amp;apos;t do too much you
couldn&amp;apos;t have already done without them. Having threads be isolated from
eachother and share information primarily by passing messages makes them really
easy to work with. They also help with a lot of Unix problems like waiting for
events from multiple sources.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
I also learned some SQL. For this project I used SQLlite, which made
things nice and easy since it doesn&amp;apos;t have a server. I got to read their
documentation, which they decided to use flowcharts to describe syntax with for
some reason. I think SQL queries are a pleasant thing to write, though. Maybe
my opinion will change If I ever have to write some more complex queries. It
felt a bit awkward to deal with weirdly-formatted or (more likely) out-of date
tables in the SQL database. Your SQL queries seem to assume that you know for
sure what SQL table you have and how they&amp;apos;re organized, and doesn&amp;apos;t give many
introspective tools to verify that meta-information. Storing a version number
in the table and panicking if it&amp;apos;s wrong seems to be a perfectly workable
solution, though. I also had to store some passwords in the database. I
expected this to be hard, but after a bit of research it didn&amp;apos;t end up being
very bad. I just needed to use a function to hash the password when it goes in
and unhash it when it goes out.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
I also made a text protocol for the chess server. I think it overall went
fairly well, although I had some trouble with race conditions. Specifically,
what happens if a client sends a command relating to an object which has ceased
to exist. I ended up having the client send an ID number with each message and
having the server send back a confirmation message with that ID that indicates
any errors. It seems to work, although I haven&amp;apos;t specifically tested many of
those race conditions, so it may break in some cases.
&lt;/p&gt;
&lt;h2 class=&quot;snx-heading&quot;&gt;
Studying Containers
&lt;/h2&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
I did some research about the Cloud and how it separates everything into
cute little Containers. They all get to do their own thing without caring about
what the computer they&amp;apos;re running on thinks. I actually expected software
running on the cloud to require design using some special capacities to
interface with the Super Cloud Overlords with cool API&amp;apos;s, but it turns out they
don&amp;apos;t. For the most part, it&amp;apos;s just the infrastructure they&amp;apos;re running on
that&amp;apos;s different, and they can usually just be run directly on your computer if
you try hard enough, which makes local testing easy.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
I started by researching Kubernetes, and I learned plenty about the broad
design of cloud infrastructure that way, but it was a bit too complex for me
starting out, so I decided to research Docker to begin with instead. Docker is
surprisingly easy to use, both to run images and to create new ones. I found it
a bit inefficient at times, though, although Docker tries it&amp;apos;s best to cache
things. I didn&amp;apos;t like how much work was given to a daemon with root privileges
to do. Also, the speed at which my root partition filled up was impressive. I
ended up symlinking docker&amp;apos;s storage dirs to my home partition so I would&amp;apos;t
run out of space.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
I also learned how much I hate capitalists. Stop talking about your weird
&amp;quot;solutions&amp;quot; and &amp;quot;business logic&amp;quot; and &amp;quot;data lakes&amp;quot; and whatever else.
&lt;/p&gt;
&lt;h2 class=&quot;snx-heading&quot;&gt;
Messaging Program
&lt;/h2&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
This is what I&amp;apos;m working on right now. A &amp;quot;cloud-native&amp;quot; service that very
simply gives you a chatbox you can talk in. When you have multiple little
micro-services all talking to each other, things start to get very complex very
quickly. One problem I ran into is propagating messages to different instances
of these microservices (in my case literal &amp;quot;messages&amp;quot; from the user). After
thinking about the problem for a few moments I realized that it&amp;apos;s not a trivial
one to solve, and I started looking for other people&amp;apos;s solutions to the
problem. There are plenty of them, as expected, and they all have massive
codebases. I don&amp;apos;t know what these services manage to do to make the task of
passing around messages as complex as they do, but that&amp;apos;s an investigative
adventure for another day.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
I&amp;apos;m trying to make this thing as reliable as I possible can. No missed
messages in the client or anywhere in the servers. I haven&amp;apos;t gotten to the
part where that really matters yet, so we&amp;apos;ll see how that goes.
&lt;/p&gt;
&lt;h2 class=&quot;snx-heading&quot;&gt;
Future
&lt;/h2&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
I want to learn to use more tools, is really the biggest thing. There&amp;apos;s
lots of them out there and I&amp;apos;m still a baby sysadmin. I also want to learn more
about what my Programmer ancestors have been doing and read the source code of
plenty of servers to absorb Good Ideas.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
In the distant future, I&amp;apos;ll be a Hot, Popular, Cute Sysadmin Witch with
Four Girlfriends. I think all of the work here only helps with the Sysadmin
part, but this is a very real future that will definitely happen.
&lt;/p&gt;

	</description>
</item>
<item>
	<title>Finding a good email setup and ranting about user-friendliness</title>
	<link>https://lunacb.house/2022-06-28.html</link>
	<pubDate>2022-06-28 21:51:25 EDT</pubDate>
	<description>
		&lt;p class=&quot;snx-paragraph&quot;&gt;
Whenever I need to read and send emails my usual solution is an awkward
and annoying trip to a web browser to visit my email provider&amp;apos;s web-app. A
proper solution would be to find a good desktop client to use, but I don&amp;apos;t work
with many emails in the first place so it&amp;apos;s never been much of a priority. I
used thunderbird for a while but it&amp;apos;s a big and bloated for me. The one mail
user agent that I&amp;apos;ve put a decent amount of effort into trying to use in the
past is neomutt.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
neomutt is awkward to configure though, especially if your goal is just
to read emails and not to dig through piles of documentation to gain a full and
comprehensive understanding of neomutt. Determining how to actually point it to
your mail server in the first place isn&amp;apos;t made very easy to figure out. On the
official website&amp;apos;s documentation, the information is found under the
generically named &amp;quot;Optional Features&amp;quot; subsection, following a couple of
paragraphs describing how to decide which SSL/TLS library to use for encryption
(a). Using multiple accounts at once has pretty bad support too, requiring that
you read a bunch of documentation on the
&lt;code class=&quot;snx-text-code&quot;&gt;
account-hook
&lt;/code&gt;
command and similar
and use them to write an error-prone configuration file manually stitching
together all your different profiles. Part of the cause of these problems is
that
&lt;i class=&quot;snx-text-italic&quot;&gt;
(neo)
&lt;/i&gt;
mutt is well over two decades old and has some of its features
stuck in the last millennium. mutt didn&amp;apos;t even have built in IMAP/POP3/etc.
support when it started. After some lackluster configuration attempts I
eventually gave up at using neomutt practically.
&lt;/p&gt;
&lt;p class=&quot;snx-path-p&quot;&gt;&lt;a class=&quot;snx-path-a&quot; href=&quot;https://neomutt.org/guide/optionalfeatures.html&quot;&gt;
(a) &amp;quot;Optional Features&amp;quot; from neomutt
&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
Following a recent burst of motivation, I decided to look for some
different mail clients, and landed on a newer program,
&lt;code class=&quot;snx-text-code&quot;&gt;
aerc
&lt;/code&gt;
(b). I
started the program and it gave me an interactive prompt asking for my email,
IMAP server, etc., and after giving that, it told me how to make another
account if I desired to and asked if I wanted to open the tutorial, which is a
short manpage listing a dozen or so keybindings and short descriptions of the
different menus you can visit. All of the learning and configuration that was
required for use of the program was finished in the first couple minutes of me
starting it. This is a much better experience than neomutt. Despite that, aerc
has a lot of similarities to neomutt in design principles. They both provide a
long list of configuration options and commands allowing for a high degree of
customizabilty.
&lt;/p&gt;
&lt;p class=&quot;snx-path-p&quot;&gt;&lt;a class=&quot;snx-path-a&quot; href=&quot;https://aerc-mail.org/&quot;&gt;
(b) aerc
&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
The problem with documentation in neomutt as opposed to aerc is not that
it has too many features, or too much documentation, or even that the
documentation is too confusing. The problem is that neomutt puts a lot of
friction between a new user and the things they&amp;apos;re intending to do with the
software. The path of least resistance to start using a mail client is to fill
out the information required to connect to the server and to learn how to read
and send messages. A good program will anticipate those requirements and put
the information needed to execute them within easy reach. Users may also have a
long-term goal of gaining a higher level of control and customizability over
their software, and for that a different, more involved and complete, set of
information needs to be provided. neomutt prioritizes that long-term goal and
provides poorly for the short-term one.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
The delivery of the information a new user might need doesn&amp;apos;t necessarily
have to be done the way aerc does it, by providing a &amp;quot;helping hand&amp;quot; within the
program itself. I tend to be skeptical of things like that in simple
command-line utilities, for example one that provides suggestions for
likely-misspelled commands or arguments, because it can increase complexity,
although I don&amp;apos;t care too much about that as long as it doesn&amp;apos;t get annoying.
The same effect can be achieved with good external documentation.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
So, the conclusion to my email journey is aerc.
&lt;/p&gt;

	</description>
</item>
<item>
	<title>Juggling unix child processes</title>
	<link>https://lunacb.house/2022-06-13.html</link>
	<pubDate>2022-06-23 17:44:05 EDT</pubDate>
	<description>
		&lt;p class=&quot;snx-paragraph&quot;&gt;
I started writing a C program, sockterm, a couple of days ago that
creates a socket and runs shell scripts sent to it by other processes through
that socket. The idea is that you can open a pseudoterminal in your favorite
window manager/terminal multiplexer and decide what program to put in it
whenever convenient, for example to run a compiler for some source code when
you trigger a keybinding.
&lt;/p&gt;
&lt;p class=&quot;snx-path-p&quot;&gt;&lt;a class=&quot;snx-path-a&quot; href=&quot;https://codeberg.org/lunacb/sockterm&quot;&gt;
sockterm
&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
Sockterm has to reliably detect both when there&amp;apos;s an update on the socket
and when the currently running program has died. A newly sent shell script is
allowed to replace a currently running one, and a program can connect to the
socket and be notified if the child process dies or is replaced by someone
else, so waiting for both socket updates and child process updates need to
happen simultaneously. The socket events can be handled with
&lt;code class=&quot;snx-text-code&quot;&gt;
poll
&lt;/code&gt;
, and
&lt;code class=&quot;snx-text-code&quot;&gt;
EINTR
&lt;/code&gt;
can be handled to check if a
&lt;code class=&quot;snx-text-code&quot;&gt;
SIGCHLD
&lt;/code&gt;
was sent.
&lt;/p&gt;
&lt;pre class=&quot;snx-code&quot;&gt;
// remember what signal was caught
int raised_signal = -1;
void signal_handler(int signal)
{
	raised_signal = signal;
}
&lt;/pre&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
and later:
&lt;/p&gt;
&lt;pre class=&quot;snx-code&quot;&gt;
if(poll(fds, nfds, -1) == -1) {
	if(errno == EINTR &amp;amp;&amp;amp; raised_signal == SIGCHLD) {
		// handle the zombie process
	}
}
&lt;/pre&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
This only works, however, if the child process dies while
&lt;code class=&quot;snx-text-code&quot;&gt;
poll
&lt;/code&gt;
is
blocking. If it happens any other time, then the fate of the child will be
unknown to sockterm. This could be solved by handling the dead child in the
signal handler function instead of from poll, but that would open up a whole
range of race conditions. We need to be able to decide when and how one of
these events will sent without missing any. So instead, I did what
&lt;code class=&quot;snx-text-code&quot;&gt;
poll
&lt;/code&gt;
does best, and used another file descriptor. Specifically, a pipe.
&lt;/p&gt;
&lt;pre class=&quot;snx-code&quot;&gt;
void signal_handler(int signal)
{
	raised_signal = signal;
	if(raised_sig == SIGCHLD) {
		write(pspipe[1], &amp;quot;n&amp;quot;, 1);
	}
}
&lt;/pre&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
Update: I didn&amp;apos;t think I came up with a revolutionary solution, and I was
right.
&lt;/p&gt;
&lt;p class=&quot;snx-path-p&quot;&gt;&lt;a class=&quot;snx-path-a&quot; href=&quot;http://cr.yp.to/docs/selfpipe.html&quot;&gt;
People came up with this in the 1990&amp;apos;s.
&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
This way,
&lt;code class=&quot;snx-text-code&quot;&gt;
pspipe
&lt;/code&gt;
, a previously created pipe, will have new data
ready whenever a SIGCHLD is caught, and
&lt;code class=&quot;snx-text-code&quot;&gt;
poll
&lt;/code&gt;
can detect that if it isn&amp;apos;t
blocking when the signal is sent. Then, once it&amp;apos;s detected, poll can just read
all the pending data from the pipe so the event isn&amp;apos;t triggered again instantly
next poll, and handle the event. This introduces a nice selection of potential
race conditions too, though, such as if a new signal is sent while the current
one is being handled after
&lt;code class=&quot;snx-text-code&quot;&gt;
poll
&lt;/code&gt;
, or if multiple are sent before
&lt;code class=&quot;snx-text-code&quot;&gt;
poll
&lt;/code&gt;
runs a gain, but it can probably be made workable, despite the fact
that it&amp;apos;s probably very bug-ridden in it&amp;apos;s current state.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
The problems aren&amp;apos;t done there though. The design of sockterm is to have
a single child process running at any given time. If one is already running
when another is supposed start, then the running child has to be killed first.
Unfortunately, a lot of programs don&amp;apos;t handle signals in a way that works well
with that. Killing bash, for example (or many other shells I&amp;apos;d imagine) with a
SIGTERM doesn&amp;apos;t actually kill bash&amp;apos;s children, only bash itself. So, if we ran
something like
&lt;code class=&quot;snx-text-code&quot;&gt;
/bin/sh -c yes
&lt;/code&gt;
on sockterm and then sent a SIGTERM to the
shell,
&lt;code class=&quot;snx-text-code&quot;&gt;
yes
&lt;/code&gt;
would continue to clog up the terminal screen for all of
eternity until killed directly. There&amp;apos;s a fairly easy (and hacky) solution to
this, which is to simply instead do
&lt;code class=&quot;snx-text-code&quot;&gt;
/bin/sh -c &amp;apos;exec program&amp;apos;
&lt;/code&gt;
, so the
shell gets replaced by
&lt;code class=&quot;snx-text-code&quot;&gt;
program
&lt;/code&gt;
and the pid held by sockterm is of the
program you actually wanted to run in the first place. Now there&amp;apos;s another race
condition, though, if the shell is killed before it gets a chance to
&lt;code class=&quot;snx-text-code&quot;&gt;
exec
&lt;/code&gt;
, So this is still a sub-optimal solution. It should work most of the
time though...
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
...except when it doesn&amp;apos;t. Even if an interactive program is signaled to
die correctly, it still might not handle that signal in a way that would be
helpful. For example,
&lt;code class=&quot;snx-text-code&quot;&gt;
man
&lt;/code&gt;
spawns a child process to act as a pager for a
manual entry. If the
&lt;code class=&quot;snx-text-code&quot;&gt;
man
&lt;/code&gt;
is killed with a signal, it does die, but the
pager doesn&amp;apos;t, so we&amp;apos;re left with the same problem as with the shell. Even if a
signal would kill all the right processes, they might not kill themselves
correctly. Vim breaks your terminal when sent a SIGTERM, for example. If you
were to run the following script:
&lt;/p&gt;
&lt;pre class=&quot;snx-code&quot;&gt;
vim; echo first; echo second
&lt;/pre&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
&lt;i class=&quot;snx-text-italic&quot;&gt;
(on a shell other than bash, which seems to fix your terminal for you)
&lt;/i&gt;
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
and sent a TERM to vim, the output would look like this:
&lt;/p&gt;
&lt;pre class=&quot;snx-code&quot;&gt;
Vim: Caught deadly signal TERM
Vim: Finished.
Terminated
          first
               second
&lt;/pre&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
So ideally you would also need to attempt to fix your terminal before
trying to run the next program.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
Anyways, that was fun. I&amp;apos;ll probably try to find a proper set of
solutions to all the brokenness eventually if I don&amp;apos;t give up.
&lt;/p&gt;

	</description>
</item>
<item>
	<title>Spellcaster encounter</title>
	<link>https://lunacb.house/2022-05-28.html</link>
	<pubDate>2022-05-29 17:13:52 UTC</pubDate>
	<description>
		&lt;p class=&quot;snx-paragraph&quot;&gt;
Here&amp;apos;s a tiny horror story I wrote. I&amp;apos;ve been practicing writing fiction
on-and-off for a while, but I&amp;apos;ve never really gotten anything into a finished
state before now. If you read this then you should constructively criticize it
so I can become less bad.
&lt;/p&gt;
&lt;h2 class=&quot;snx-heading&quot;&gt;
STORY START
&lt;/h2&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
Another restless night for the woman. She sits in her cramped apartment&amp;apos;s
kitchen, with a half-eaten bowl of instant ramen on the counter in front of
her, looking out into the pitch-black darkness through a sliding glass door.
From outside, the synthetic glow of the kitchen light feels quite inviting, as
home-interiors often do. The woman slips another bundle of ramen noodles into
her mouth and considers the chances of a real-life monster clawing its way up
to the sliding glass door to gobble her up, like in the horror movie she just
finished watching. This does raise some interesting questions, however, because
the work&amp;apos;s screenwriter was able to take a number of artistic liberties in their
film due to their absolute control over its universe and the way in which its
viewers would perceive it, specifically by showing the story both from the
perspective of the victim and of the monster, allowing a greater degree of
control over the presentation of information. This would not, however, be
possible in real life from the perspective of an individual trapped in a
monster scenario, where the information about the world known by that
individual would be limited to what can be experienced with the senses. So,
this monster would require some sort of special properties to replicate the
same narrative advantages as something watched in a theater. This problem could
potentially be solved by a scenario in which the monster were somehow
psychically linked to the victim, almost as if they were a singular entity.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
&lt;i class=&quot;snx-text-italic&quot;&gt;
Her soul tightens.
&lt;/i&gt;
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
So, with this in mind, the woman starts to think, what would such a
situation look like in practice? What if, right now, a monster were to appear
and walk right up to that sliding glass door and do something terrible?
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
And I do agree, this is a very interesting question. I can see that
synthetic fluorescent light a few dozen feet away and I inhale the smell of
summertime grass and roses and with the wind blowing across my exposed bloody
spine and my spotty fur I jump swiftly to the porch of that house just within
the reach of the light shining from within, and she sees me. Eyes widened, she
wants to scream but she instead stays still and as calm as she can be, takes a
deep breath, and looks away. She thinks, what would the victim of this scenario
have as a defense? There wouldn&amp;apos;t be one, I think, because this monster always
wins, and I begin to tear my claws through her skillfully-prepared protective
enchantments. The woman is jolted by the sound and her heart beats faster and
her body tenses and her mind feels blurred but she expects that I do have a
weakness, because we are connected and that connection can be severed, but I
laugh and ram through another barrier with the certainty that my connection, my
grasp on her being, is stronger than life and cannot be severed. She stops, and
she takes one moment, two, and she composes herself and looks into the air
where she knows lies the invisible tendrils of our intertwined souls, and does
not cut and sever these connecting tendrils but instead takes her chair from
underneath herself and swings forcefully towards them, and they shatter and
melt back into their respective owners.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
I lay on the floor with my heart beating and my hand still clutching the
chair. It&amp;apos;s over. I let go of the chair, relax, and breathe a sigh of relief.
Tomorrow I&amp;apos;ll ponder how a demon like that managed to follow me home, but for
now I&amp;apos;ll just make my way to bed and get some sleep.
&lt;/p&gt;

	</description>
</item>
<item>
	<title>Hacking volume and brightness status indicators into existence</title>
	<link>https://lunacb.house/2022-05-13.html</link>
	<pubDate>2022-05-17 04:26:35 UTC</pubDate>
	<description>
		&lt;p class=&quot;snx-paragraph&quot;&gt;
A while ago I wanted to make a status indicator show up on my laptop&amp;apos;s
screen whenever I change the volume or brightness. The kind that shows a pretty
percentage bar in the middle of the screen. This would come for free if I had a
big fancy desktop environment to do it for me, but unfortunately I&amp;apos;m a Cultured
Tiling Window Manager User, so instead I had to spend hours of my life reading
documentation and writing configuration files and shell scripts until I got it
working.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
Note: Some scripts and configurations are ommitted because I&amp;apos;m too lazy to
make my chaotic dotfiles presentable to the public.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
Actually displaying something on the screen is the easy part, because
someone&amp;apos;s already done it for me. I&amp;apos;m using sway, which is a wayland
compositor, so I can use wob to do the displaying (a). wob will read a series
of lines into standard input, each of containing a number representing a
percentage to display and optionally a descrption of what colors should be
used to display it.
&lt;/p&gt;
&lt;p class=&quot;snx-path-p&quot;&gt;&lt;a class=&quot;snx-path-a&quot; href=&quot;https://github.com/francma/wob&quot;&gt;
(a) wob
&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
Determining what number to send over to wob takes a bit more effort but
still isn&amp;apos;t too difficult. The needed numbers can be gotten with a program from
sutils (a), and from brightnessctl (b).
&lt;/p&gt;
&lt;pre class=&quot;snx-code&quot;&gt;
# volume:
volume -f &amp;apos;%i&amp;apos;
&lt;/pre&gt;
&lt;pre class=&quot;snx-code&quot;&gt;
# brightness:
brightnessctl -m -d acpi_video0 | awk -F, &amp;apos;{ print $4 }&amp;apos; | sed &amp;apos;s/.$//&amp;apos;
&lt;/pre&gt;
&lt;p class=&quot;snx-path-p&quot;&gt;&lt;a class=&quot;snx-path-a&quot; href=&quot;https://github.com/baskerville/sutils&quot;&gt;
(a) sutils
&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;snx-path-p&quot;&gt;&lt;a class=&quot;snx-path-a&quot; href=&quot;https://github.com/Hummer12007/brightnessctl&quot;&gt;
(b) brightnessctl
&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
The next step was deciding how to actually run wob. It should ideally be
run as a daemon, and there should be a way to get a command piped into it from
any other process on the system. That ended up being a bit difficult though. my
first attempt was to make a FIFO file and to read that into wob&amp;apos;s standard
input, with the intention of letting any program open it, write to it, and
close it again. This causes a problem though, since if a process closes the
FIFO file after writing to it, an EOF is sent, which means once that process is
done no others can talk to the wob daemon. So, I wrote a small C program,
fifoexec (a), which would run another program, pipe the contents of a FIFO file
into it, and re-open that FIFO file if an EOF indicator was reached instead of
dying. This worked exactly as intended.
&lt;/p&gt;
&lt;pre class=&quot;snx-code&quot;&gt;
rm -f &amp;quot;$fifo_path&amp;quot;
mkfifo &amp;quot;$fifo_path&amp;quot;
exec fifoexec &amp;quot;$fifo_path&amp;quot;
&lt;/pre&gt;
&lt;p class=&quot;snx-path-p&quot;&gt;&lt;a class=&quot;snx-path-a&quot; href=&quot;https://codeberg.org/lunacb/miscbin/src/branch/master/fifoexec.c&quot;&gt;
(a) fifoexec
&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
Now, anyone can just
&lt;code class=&quot;snx-text-code&quot;&gt;
echo percentage &amp;gt; &amp;quot;$fifo_path&amp;quot;
&lt;/code&gt;
and it&amp;apos;ll
show up on the screen. I wouldn&amp;apos;t be suprised if I made this much more
complicated than it needed to be.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
The final step should be pretty easy in theory. Take the keybindings the
window manager has already been told to use to adjust volume and brightness,
and additionally tell wob what the new values are when these keybindings are
triggered. And exactly that was done for volume, which worked as expected! The
brightness keybindings, however... did not exist. They showed up nowhere in the
window manager configuration file. Through some sort of black magic, they
instead simply worked. After a bit of searching I found the real reason: my
thinkpad t400 uses the Linux kernel module &amp;quot;thinkpad_acpi&amp;quot;, which handles the
backlight keybindings, among other things, and also tells me I shouldn&amp;apos;t mess
with them (a):
&lt;/p&gt;
&lt;blockquote class=&quot;snx-quote&quot;&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
Don&amp;apos;t mess with the brightness hotkeys in a Thinkpad. If you want
	notifications for OSD, use the sysfs backlight class event support.
&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
The driver will issue KEY_BRIGHTNESS_UP and KEY_BRIGHTNESS_DOWN
	events automatically for the cases were userspace has to do something to
	implement brightness changes. When you override these events, you will
	either fail to handle properly the ThinkPads that require explicit action
	to change backlight brightness, or the ThinkPads that require that no
	action be taken to work properly.
&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p class=&quot;snx-path-p&quot;&gt;&lt;a class=&quot;snx-path-a&quot; href=&quot;https://docs.kernel.org/admin-guide/laptops/thinkpad-acpi.html&quot;&gt;
(a) thinkpad-acpi documentation
&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
Kernel hackers are scary, so I&amp;apos;ll try not to defy their authority. Instead
I&amp;apos;ll just make a udev rule that talks to wob whenever the brightness is
changed:
&lt;/p&gt;
&lt;pre class=&quot;snx-code&quot;&gt;
ACTION==&amp;quot;change&amp;quot;, 
SUBSYSTEM==&amp;quot;backlight&amp;quot;, 
RUN+=&amp;quot;/usr/local/bin/wob_backlight&amp;quot;
&lt;/pre&gt;
&lt;p class=&quot;snx-paragraph&quot;&gt;
And that just about does it! I&amp;apos;m still suprised at how resilient the setup
managed to be. I don&amp;apos;t think it&amp;apos;s broken once so far. I had fun with it!
&lt;/p&gt;

	</description>
</item>

	</channel>
</rss>
