Yesterday I had a program fail because an update had modified my PATH. This led to an hours long investigation into just how my system PATH is getting generated.
The system PATH is a list of directories that will be searched when you run a binary from the command line. I live in a tmux session running on top of the fish shell, in alacritty, on xfce, in manjaro, an arch based, linux distribution. There are many agents that can monkey with my PATH.
You can view your current PATH with:
echo $PATH
When I ran this during the failure I saw this:
na@hydra ~> echo $PATH
/home/na/source/gocode/bin
/home/na/bin
.
.
.
/home/na/.pyenv/libexec/pyenv
/home/na/.pyenv/libexec
/home/na/.pyenv/shims
/home/na/.pyenv/bin
/opt/rocm/bin
.
/home/na/.pyenv/libexec/pyenv
/home/na/.pyenv/libexec
/home/na/.pyenv/shims
/home/na/.pyenv/bin
.
/home/na/.cargo/bin
/home/na/.local/bin
/usr/local/bin /usr/bin
/bin
/usr/local/sbin
/var/lib/flatpak/exports/bin
/usr/lib/jvm/default/bin
/usr/bin/site_perl
/usr/bin/vendor_perl
/usr/bin/core_perl
There were duplicates and missing paths and I wanted to know who was responsible for this mess. Unfortunately I couldn't find any good way to determine who is modifying your PATH. I wanted something like this:
~/.config/fish/config.fish added '~/bin' to your $PATH
~/.profile called '~/.cargo.env' which added '~/.cargo/bin' to your $PATH
/etc/login.defs added '/usr/bin' to your $PATH
Fish has some pretty cool debug flags, but nothing like this.
I like fish. It does a good job of shipping with batteries included, but I don't like how they handle environment variables. The fact that the first entry in their FAQ is how to view, set, and clear your environment variables illustrates the complexity.
The set command has flags to set the scope of variables to local (-l), global (-g), and function (-f). It can also use -U to set a 'universal variable' which will persist across restarts, and an -x option to export variables to child processes. They also have a helper function that will check if a PATH entry already exists before adding it again.
My $PATH had a bunch of duplicates and questionable entries. I tracked them down by grepping through my system config and dotfiles. Several hours later, here's my current PATH and where they are populated.
path where it comes from
---- -------------------
/home/na/.pyenv/bin # fish env
/home/na/.pyenv/shims # fish env
/home/na/.pyenv/libexec # fish env
/home/na/source/gocode/bin # fish env
/home/na/bin # fish env
. # ???
. # ???
. # ???
. # ???
/home/na/.cargo/bin # ~/.profile -> ~/.cargo/env
/home/na/.nix-profile/bin # /etc/profile.d/nix.fish
/home/na/.nix-profile/bin # /etc/profile.d/nix-daemon.fish
/nix/var/nix/profiles/default/bin # /etc/profile.d/nix-daemon.fish
/home/na/.local/bin # /etc/profile.d/home-local-bin.sh
/usr/local/bin # /etc/login.defs
/usr/bin # /etc/login.defs
/bin # ???
/usr/local/sbin # /etc/login.defs
/var/lib/flatpak/exports/bin # /etc/profile.d/flatpak-bindir.sh
/usr/lib/jvm/default/bin # /etc/profile.d/jre.sh
/usr/bin/site_perl # /etc/profile.d/perlbin.sh
/usr/bin/vendor_perl # /etc/profile.d/perlbin.sh
/usr/bin/core_perl # /etc/profile.d/perlbin.sh
/opt/rocm/bin # /etc/profile.d/rocm.sh
It took several hours to compile this list because some of the entries were added by child processes, and many of the settings persisted in my login shell and fish cache. Also, the PATH will be different depending on if you're running in an interactive shell or a login shell.
One result of this investigation is I removed my pyenv fish plugin. It was inexplicably adding two lists to my PATH including a path to a binary file. This raised enough red flags I just removed the plugin and manually configured the three paths in my fish config.
I also learned that .profile is automatically loaded on every login. To test modifications to this file you need to log out after making changes.
Many of the paths are set up by the system. Scripts in /etc/profile.d/ are run according to your shell and /etc/login.defs sets up some system-wide paths. I could not find who was setting up /bin. Since this is the old school binary path, it might be built into the kernel. The fish scripts found in profile.d were responsible for the nix duplicates. Duplicates aren't bad, but it's sloppy, and I like my system maintainers to be careful.
Finally, there's a bunch of '.' duplicates. I couldn't find where these were being added, and I obviously didn't bother grepping for '.'. I remember working with a windows engineer who was forced by extremity to write code for linux. He was surprised to learn that '.' wasn't in the path. I always appreciated this as a security measure. Writing:
./blow_up_the_world.bin
Is so much more deliberate than writing:
blow_up_the_world.bin
and having your system go looking for a binary that will destroy everything.
I don't know how long distros have been adding '.' to the PATH, but I would remove it if I could.
That windows engineer made his project a subdirectory in a folder called 'linsux'
You can see my updated fish config in the dotfiles project in my gitforge.
I've been writing everything in rust these days - even replacing my python scripts. When I started, I spent most of my time wrestling with the compiler, but as I've grown more comfortable with the language I've been spending more time thinking about the problems I'm trying to solve.
The tooling in rust is great. Cargo is wonderful, dependency management is sane, I write more unit tests, and the documentation is fantastic. Rust ships with the API reference and offline versions of a dozen books. You can access these docs with:
rustup docs
And you can view an offline html render of most libraries by cloning the source (or just finding it in the local cargo registry ~/.cargo/registry/) and then running:
cargo doc --open
Refactoring in rust is amazing. Once you have something locked in with types and unit tests you can make a change and the compiler will help you find and fix every reference. I recently replaced chrono and crono-tz with jiff in a library I'm working on. This dependency was deeply connected to every other module, but rust refused to compile until I'd caught every reference and when I was done, it worked on the first try.
When writing in rust it's common for programs to work as soon as you've satisfied the compiler.
Despite my proficiency I'm still sometimes confused about the syntax. I recently ran into this:
match exif.get_field(exif::Tag::Orientation, exif::In::PRIMARY) {
Some(orientation) => match orientation.value.get_uint(0) {
Some(v @ 1..=8) => println!("{} Orientation {}", filepathstr, v),
_ => eprintln!("Orientation value is broken"),
},
None => eprintln!("Orientation tag is missing"),
}
I had to look up the '@' operator in this line:
Some(v @ 1..=8) => println!("{} Orientation {}", filepathstr, v),
Apparently '@' provides pattern binding and '1..=8' is right inclusive range literal. Basically this match arm matches on an Option containing a value within a range of 1-8, and captures the match in 'v' so we can print it. The following '_' arm will match everything else, including Some(9), and None.
I found the pattern matching rules confusing at first. The idea of capturing and unwrapping a value from the left-hand side of a declaration is strange.
For example:
if let Some(color) = favorite_color {
println!("Using your favorite color, {color}, as the background");
} else {
println!("Using blue as the background color");
}
I've gotten more comfortable with this syntax, but I still have think about it.
The deref trait is amazing. It makes working with pointers painless. I'm always amazed how easy it is to pass things around by reference.
The type system is powerful, but I'm still building a full war chest of examples to refer to. Capturing behavior in the type system is a good way make the compiler work for you and is one of the main reasons people are excited to rewrite system utilities in the new language. The problem is the complexity this brings.
The kernel guys are wrestling with rust.. The seasoned c programmers don't want to have to learn and maintain a new language, but the rust guys are finding bugs and bad abstractions. in their code.
It's important to bring in new blood, but I can understand the reluctance for kernel maintainers to accept rust when their c code seems to be running fine and has been running for decades.
The language difficulty has a filtering effect among developers. I'm generally happy to replace system utilities with ones written in rust, and I'm more likely to view a project favorably if it's written in rust because the only developers that can write it are skilled by definition. As the language gains wider adoption the quality might come down, but rust has found a sweet spot.
Despite the complexity and compiler constantly telling me I've done something wrong, programming in rust is fun. I haven't felt this excited about a language since python.
A Masterpiece in Disarray: David Lynch’s Dune—An Oral History - Max Evry. I stand by the somewhat facetious claim that Lynch's dune is my favorite movie of all time. I'm sad we never got to see Lynch's cut. He had 4-5 hours of footage and Dino cut it down to 90 minutes, so theaters could show it more times in a day. Dino cut so much it stopped making sense. Then, to try to fix this they added an introduction by the princess, and all the characters got internal monologues. When this still failed to help they sent pamphlets to movie theaters with a glossary of terms. It was Dino's decision to add the terrible scene at the end where Paul makes it rain.
Lynch was working on story boards for the follow-up movies. As someone said in the book, "Why don't they just give David money?". I agree, we should have given David more money. There have been various fan edits of Dune over the years. The Dune 1984 Alternative Edition Redux doesn't make it any more comprehensible, but it removes some of Dino's bad additions. * You Suck - Christopher Moore. I picked this book out of the discarded book bin at the NOLS campus in Baja before our flight home and finished it before we landed in Monterey. I laughed more than a few times, but the humor began to grow stale near the end.
Today we have more fine literature than I could consume in a lifetime. You could produce this show for almost no money.
I enjoyed this game so much more after I started over with a new character. It's beautiful and the characters, variety, design, and animation is amazing. It may be an illusion caused by the difficulty, but it seems much larger than Skyrim. When every encounter can kill you in seconds, you tend to explore very carefully.
I don't consider gaming a core part of my identity. I don't have the best reflexes and I prefer to play games in casual mode. Elden Ring doesn't have a causal mode. I selected my first character based on an online suggestion that a magic using astrologer was the best character for people new the series. This was a mistake. As a glass cannon with a limited pool of magic I died hundreds of times. I gave up at the second big boss (out of a dozen? Twenty? This game is huge) after dying 50-60 times. After each death it would send me back to my save point. It took about a minute to run from the save point back to try the fight again and this gets pretty tedious after 59 failures.
The game drops you into a strange mythology with baffling terminology. You start with a Furlcalling finger remedy, gold-pickled fowl foots, memory of grace, and a flask of crimson tears. Your inventory includes rune arcs, starlight shards, reusable cracked pots, ashes of war, perfume bottles (as weapons), and bell bearings. An NPC offered to hug me and then gave me Baldachins blessing which, for a long time I thought was a status effect, but which is actually an item that has lowered my HP by 5%. Later in the game after 20 tries, I managed to defeat a difficult boss and noticed coffin in the corner. Approaching it, I was offered the option to climb inside and take a nap, then it played a cutscene showing the coffin flying to the top of a waterfall on a string of magical symbols. You speak to a creature known as the two fingers which is interpreted by a withered crone with empty eye sockets.
The game keeps the line between single and multiplayer gameplay deliberately fuzzy. The ground was littered with bloodstains showing places where other players have died, and white sigils offering cryptic advice. The sigils were written by other players using a deliberately limited vocabulary, which makes them feel cryptic and alien. Also, because they are written by the general public, they're often misleading or crude.
Other players can spontaneously join your game and kill you (though I'm not sure if these are always controlled by other people), and you can invite other people to help you fight.
Most creatures in the game are deliberately designed with crazy flowing cloaks and chains, so parts of their model continue to move after the character has stopped. The designers call it secondary movement, and it's meant to make it more difficult to visually parse the creatures you're fighting. Each monster in the game has a complicated move-set which needs to be understood and responded to within particular animation frames to avoid their attacks. I've heard Elden Ring accurately described as Dance, Dance Revolution the RPG.
Check out these fights with Margit and Godrick. Be sure to stick with the Godrick video until 2:30 when he enters his second phase.
The size and weirdness of the setting, the number of unique monsters (lists online have it at 120 creatures in the base game), and the difficulty, makes you slow down and appreciate the work that went into it. I kind of want to start over with a different character, but it is a huge time sink and I'm not sure if I have the patience, time, and skill to enjoy it any better a third time around.
Cairn (the full game will be released in 2025, but you can play the free demo on steam) is a rock climbing game which somehow manages to capture the feeling of actual rock climbing. The game doesn't play a soundtrack or artificial sounds, only the sound of the wind, your labored breathing, and the slap and scrape of your hands and feet on the wall. It also eschews a stamina bar and other visual indicators, opting instead to have your character grunt and breath harder, slip on the rock, and start trembling when they're getting tired. Playing the game is as meditative as actual climbing. You spend your time carefully positioning your hands and feet and pushing your luck before attaching a safety line.
This is a free, turn-based RPG by the co-creator of the fable series for the xbox. For a free game it's surprisingly deep. This has been my steam deck go to for a few minutes each night before bed for the last several weeks.
This game is so buggy it's hard to recommend, but the developer is still releasing updates and the premise has tremendous potential. You play as a detective in a living city solving crimes by collecting clues, breaking and entering, taking fingerprints, and interviewing people. The people have jobs and places where they live, and they seem to commit crimes organically.
You will hear about a murder and race to the crime scene to collect evidence before the cops arrive, then stake out suspects, disable security systems, hack into their computers, crack their safes, take fingerprints, bribe witnesses, and crawl through vents to gather enough to turn in a case for a reward. The game takes it's time. You might want to follow a suspect to see where they work but if it's 6pm you'll have to find some place to sit down and wait for them to get up and go to work in the morning.
Unfortunately the game is pretty buggy. In my last case I arrived at the murder scene and caught the perpetrator leaving the apartment while the police were inside investigating the scene. I gave chase and caught him, and he told me his name, but before I could handcuff him he took off running, eventually drifting through the floor.
In another case I called a phone number to accept a job and was told to go to a phone booth on a street at 16:06. It was 16:06 already, and it took me a few minutes to find the street on the map. As I was running up to the booth it said 'job failed' but when I picked up the phone to call the number again someone answered and started giving me the job information. I was told there was a suitcase nearby, but I couldn't find it, so I reloaded from quicksave and tried again. This time I got a different prompt to complete the job and the suitcase was right there.
Citizens are trigger-happy. I visited a suspect's laboratory and accidentally stepped a few inches through the doorway. All the office workers instantly started screaming, everyone drew guns, and started blasting away.
As you collect clues you put them onto a cork board connected with multicolored strings. It's a nice effect and generally useful. I'm hoping they clean up the bugs. It seems every time I play a scenario I encounter a few game breaking issues. It's so bad it's hard to know if you aren't making any progress because you've followed the wrong clues or because the game is broken.
Peglin is a pachinko roguelike. I've been playing this for a year or so and the devs keep expanding upon this simple template. It's easy to jump in and there are enough game-changing modifiers it's always fresh. The gameplay is simple, but you get wacky combinations often enough it remains entertaining.
age is a modern file encryption tool that can be used as a replacement for gpg. Unfortunately my particular use case isn't explicitly described in the examples. Here is how to encrypt a file with a password protected private key.
make a password protected key file:
age-keygen | age -p > sensitive.key
get the public key from this file:
age -d sensitive.key | age-keygen -y
encrypt to this public key:
age -r age13te9f7kd3x88e3lkaq5rf46hf6eeqhrp5x7e2j4z7j65gzv36sjqgqmv9a sensitive.plaintext > sensitive.age
decrypt using the password protected key file:
age -d -i sensitive.key sensitive.age > sensitive.plaintext
shred it when we're done:
shred -u /home/na/sensitive.plaintext
You could also do symmetric encryption, but this sort of two-factor authentication is slightly more secure against rubber hose cryptanalysis
Since every search engine now offers an often unwanted AI summary as the first result of your search, and corporations are deathly afraid of their LLMs generating anything that is not HR approved corp-speak. You can get rid of the AI search by swearing.
In google:
In duck duck go (which uses bing as it's backend):
Arnie drove us down to Chatsworth in his tech filled van to visit Kayla for Thanksgiving. Every day we would take Poncho for a walk through the park behind their rented house in the Simi Valley. Walking with Rian, we came across a tree full of ripe black olives. The limbs were heavy, and the ground was littered with them. I picked a few and then filled my pockets with as many as I could carry and suggested we return with a bag, so I could collect more. I wanted to try pickling olives.
The next day Amanda, Rian, and I returned, and I kept them waiting while I foraged, combing the ripe berries from the dry leaves. I would have gathered more, but I felt guilty making them wait, and it was difficult enough to get the ones I collected back home on the train.
I opened a half dozen olive pickling recipes online and selected this one. The process has taken a few months. I started by discarding the damaged berries and slicing the rest with three or four vertical cuts to help the oleuropein, a nasty tasting chemical, leach out of the skin. Then I soaked them in 9 water baths, changing the water every day.
They just finished the last of four week-long soaks in brine and I bottled them in three large resealable jars with a mixture of brine and balsamic vinegar and apple cider. They should be ready to eat in a week. The ones I tried after brine baths already tasted fine.
For the effort put into them, it would have made more sense to do two or ten times more. If I lived closer to that olive tree I would have collected gallons and made a press to squeeze the oil out.
I now have three jars of olives crouched on the floor by the cat feeder in dark pools of spiced brine. They will garnish my meals and I will eat them whole as an afternoon snack. In future Novembers, I will pay more attention to olive trees.