<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Jayng9663</title><link>https://jayng9663.github.io/blog/</link><description>Recent content on Jayng9663</description><generator>Hugo -- gohugo.io</generator><language>en-us</language><lastBuildDate>Wed, 08 Apr 2026 16:10:31 -0700</lastBuildDate><atom:link href="https://jayng9663.github.io/blog/index.xml" rel="self" type="application/rss+xml"/><item><title>Build and Run on kernel using QEMU</title><link>https://jayng9663.github.io/blog/p/build-and-run-on-kernel-using-qemu/</link><pubDate>Wed, 08 Apr 2026 16:10:31 -0700</pubDate><guid>https://jayng9663.github.io/blog/p/build-and-run-on-kernel-using-qemu/</guid><description>&lt;p&gt;Just for personal note, haven&amp;rsquo;t test on others.&lt;/p&gt;
&lt;h2 id="kernel-config"&gt;&lt;a href="#kernel-config" class="header-anchor"&gt;&lt;/a&gt;Kernel Config
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;make defconfig &lt;span class="nv"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;clang
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;if want to include other module which is not enable be default in defconfig. run for e.g.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./scripts/config --module CONFIG_MAC80211_HWSIM
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./scripts/config --module CONFIG_IWLWIFI=y
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./scripts/config --module CONFIG_IWLWIFI_LEDS=y
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./scripts/config --module CONFIG_IWLDVM=m
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./scripts/config --module CONFIG_IWLMVM=m
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="build-kernelsh"&gt;&lt;a href="#build-kernelsh" class="header-anchor"&gt;&lt;/a&gt;build-kernel.sh
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; -e
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;make &lt;span class="nv"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;clang -j&lt;span class="k"&gt;$(&lt;/span&gt;nproc&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;python3 scripts/clang-tools/gen_compile_commands.py
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Done — bzImage ready at arch/x86/boot/bzImage&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;For subsequent small changes just run &lt;code&gt;make CC=clang -j$(nproc)&lt;/code&gt; directly.
Make only recompiles changed files, so a single &lt;code&gt;.c&lt;/code&gt; change takes a few seconds.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="raw-kernel--busybox-initramfs"&gt;&lt;a href="#raw-kernel--busybox-initramfs" class="header-anchor"&gt;&lt;/a&gt;Raw Kernel + Busybox Initramfs
&lt;/h2&gt;&lt;p&gt;QEMU loads the kernel and a cpio archive, the kernel unpacks
it into a tmpfs, runs &lt;code&gt;/init&lt;/code&gt;, and drops you into a busybox shell.&lt;/p&gt;
&lt;h3 id="build-initramfssh"&gt;&lt;a href="#build-initramfssh" class="header-anchor"&gt;&lt;/a&gt;build-initramfs.sh
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; -e
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;KBUILD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;rm -rf initramfs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir -p initramfs/&lt;span class="o"&gt;{&lt;/span&gt;bin,sbin,etc,proc,sys,dev,lib/modules&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cp /usr/bin/busybox initramfs/bin/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; initramfs/bin
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./busybox --install .
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$KBUILD&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; initramfs/init &lt;span class="s"&gt;&amp;lt;&amp;lt; &amp;#39;EOF&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;#!/bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;mount -t proc none /proc
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;mount -t sysfs none /sys
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;mount -t devtmpfs none /dev 2&amp;gt;/dev/null || mdev -s
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;echo &amp;#34;Kernel $(uname -r) booted!&amp;#34;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;exec /bin/sh
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;chmod +x initramfs/init
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; initramfs
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;find . &lt;span class="p"&gt;|&lt;/span&gt; cpio -o -H newc &lt;span class="p"&gt;|&lt;/span&gt; gzip &amp;gt; ../initramfs.cpio.gz
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ..
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;Done — initramfs.cpio.gz ready&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="bootsh"&gt;&lt;a href="#bootsh" class="header-anchor"&gt;&lt;/a&gt;boot.sh
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; -e
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;KBUILD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qemu-system-x86_64 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -kernel &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$KBUILD&lt;/span&gt;&lt;span class="s2"&gt;/arch/x86/boot/bzImage&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -initrd &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$KBUILD&lt;/span&gt;&lt;span class="s2"&gt;/initramfs.cpio.gz&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -append &lt;span class="s2"&gt;&amp;#34;console=ttyS0,115200 earlyprintk=serial,ttyS0,115200 rdinit=/init nokaslr&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -nographic &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -serial mon:stdio &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -device e1000,netdev&lt;span class="o"&gt;=&lt;/span&gt;net0 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -netdev user,id&lt;span class="o"&gt;=&lt;/span&gt;net0,hostfwd&lt;span class="o"&gt;=&lt;/span&gt;tcp::2222-:22 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -m 512M &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -no-reboot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="rebuild"&gt;&lt;a href="#rebuild" class="header-anchor"&gt;&lt;/a&gt;Rebuild
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash build-kernel.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash build-initramfs.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash boot.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Exit QEMU with &lt;code&gt;Ctrl-A X&lt;/code&gt; or run &lt;code&gt;shutdown&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="full-arch-linux-rootfs"&gt;&lt;a href="#full-arch-linux-rootfs" class="header-anchor"&gt;&lt;/a&gt;Full Arch Linux Rootfs
&lt;/h2&gt;&lt;p&gt;When you need &lt;code&gt;pacman&lt;/code&gt;, &lt;code&gt;ssh&lt;/code&gt;, or any real tooling, install Arch onto a qcow2 image and
boot your custom kernel directly into it.&lt;/p&gt;
&lt;h3 id="create-the-disk"&gt;&lt;a href="#create-the-disk" class="header-anchor"&gt;&lt;/a&gt;Create the Disk
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qemu-img create -f qcow2 rootfs.qcow2 10G
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="install-arch-from-iso"&gt;&lt;a href="#install-arch-from-iso" class="header-anchor"&gt;&lt;/a&gt;Install Arch from ISO
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qemu-system-x86_64 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -cdrom archlinux-x86_64.iso &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -boot d &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -drive &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;rootfs.qcow2,format&lt;span class="o"&gt;=&lt;/span&gt;qcow2 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -device e1000,netdev&lt;span class="o"&gt;=&lt;/span&gt;net0 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -netdev user,id&lt;span class="o"&gt;=&lt;/span&gt;net0,hostfwd&lt;span class="o"&gt;=&lt;/span&gt;tcp::2222-:22 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -m 2G &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -enable-kvm &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -no-reboot &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -vnc :0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Connect with &lt;code&gt;vncviewer localhost:5900&lt;/code&gt;. Inside the installer:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;span class="lnt"&gt;17
&lt;/span&gt;&lt;span class="lnt"&gt;18
&lt;/span&gt;&lt;span class="lnt"&gt;19
&lt;/span&gt;&lt;span class="lnt"&gt;20
&lt;/span&gt;&lt;span class="lnt"&gt;21
&lt;/span&gt;&lt;span class="lnt"&gt;22
&lt;/span&gt;&lt;span class="lnt"&gt;23
&lt;/span&gt;&lt;span class="lnt"&gt;24
&lt;/span&gt;&lt;span class="lnt"&gt;25
&lt;/span&gt;&lt;span class="lnt"&gt;26
&lt;/span&gt;&lt;span class="lnt"&gt;27
&lt;/span&gt;&lt;span class="lnt"&gt;28
&lt;/span&gt;&lt;span class="lnt"&gt;29
&lt;/span&gt;&lt;span class="lnt"&gt;30
&lt;/span&gt;&lt;span class="lnt"&gt;31
&lt;/span&gt;&lt;span class="lnt"&gt;32
&lt;/span&gt;&lt;span class="lnt"&gt;33
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;fdisk /dev/sda &lt;span class="s"&gt;&amp;lt;&amp;lt; &amp;#39;EOF&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;g
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;n
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;1
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;w
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;EOF&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkfs.ext4 /dev/sda1
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mount /dev/sda1 /mnt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# base only, no need linux package&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;pacstrap /mnt base
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;genfstab -U /mnt &amp;gt;&amp;gt; /mnt/etc/fstab
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;arch-chroot /mnt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;passwd root
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# Network (optional)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cat &amp;gt; /etc/systemd/network/20-wired.network &lt;span class="s"&gt;&amp;lt;&amp;lt; &amp;#39;NET&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;[Match]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;Name=ens3
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;[Network]
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;DHCP=yes
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;NET&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; systemd-networkd systemd-resolved
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;exit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;umount -R /mnt
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;poweroff
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="bootsh-1"&gt;&lt;a href="#bootsh-1" class="header-anchor"&gt;&lt;/a&gt;boot.sh
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;span class="lnt"&gt;14
&lt;/span&gt;&lt;span class="lnt"&gt;15
&lt;/span&gt;&lt;span class="lnt"&gt;16
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="cp"&gt;#!/bin/bash
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;set&lt;/span&gt; -e
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nv"&gt;KBUILD&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;qemu-system-x86_64 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -kernel &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$KBUILD&lt;/span&gt;&lt;span class="s2"&gt;/arch/x86/boot/bzImage&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -drive &lt;span class="nv"&gt;file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="nv"&gt;$KBUILD&lt;/span&gt;&lt;span class="s2"&gt;/rootfs.qcow2&amp;#34;&lt;/span&gt;,format&lt;span class="o"&gt;=&lt;/span&gt;qcow2 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -append &lt;span class="s2"&gt;&amp;#34;console=ttyS0,115200 earlyprintk=serial,ttyS0,115200 root=/dev/sda1 rw nokaslr&amp;#34;&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -nographic &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -serial mon:stdio &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -device e1000,netdev&lt;span class="o"&gt;=&lt;/span&gt;net0 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -netdev user,id&lt;span class="o"&gt;=&lt;/span&gt;net0,hostfwd&lt;span class="o"&gt;=&lt;/span&gt;tcp::2222-:22 &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -m 2G &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -enable-kvm &lt;span class="se"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; -no-reboot
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;SSH in with:&lt;/p&gt;
&lt;blockquote class="alert alert-note"&gt;
 &lt;div class="alert-header"&gt;
 &lt;span class="alert-icon"&gt;📝&lt;/span&gt;
 &lt;span class="alert-title"&gt;Note&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="alert-body"&gt;
 &lt;p&gt;Need to install and start openssh, and set &lt;code&gt;PermitRootLogin = yes&lt;/code&gt; in &lt;code&gt;/etc/ssh/ssh_config&lt;/code&gt;.&lt;/p&gt;
 &lt;/div&gt;
 &lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;ssh -p &lt;span class="m"&gt;2222&lt;/span&gt; root@127.0.0.1
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h3 id="rebuild-1"&gt;&lt;a href="#rebuild-1" class="header-anchor"&gt;&lt;/a&gt;Rebuild
&lt;/h3&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash build-kernel.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash build-initramfs.sh
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;bash boot.sh
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Exit QEMU with &lt;code&gt;Ctrl-A X&lt;/code&gt; or run &lt;code&gt;shutdown&lt;/code&gt;.&lt;/p&gt;</description></item><item><title>VN Presence</title><link>https://jayng9663.github.io/blog/p/vn-presence/</link><pubDate>Mon, 30 Mar 2026 01:27:09 -0700</pubDate><guid>https://jayng9663.github.io/blog/p/vn-presence/</guid><description>&lt;p&gt;&lt;a class="link" href="https://github.com/jayng9663/VN-Presence" target="_blank" rel="noopener"
 &gt;&lt;img alt="Github Repo" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://img.shields.io/badge/github-repo-blue?logo=github"&gt;&lt;/a&gt;
&lt;a class="link" href="https://www.gnu.org/licenses/agpl-3.0" target="_blank" rel="noopener"
 &gt;&lt;img alt="License: AGPL v3" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://img.shields.io/badge/License-AGPL_v3-blue.svg"&gt;&lt;/a&gt;
&lt;a class="link" href="https://en.cppreference.com/w/cpp/23" target="_blank" rel="noopener"
 &gt;&lt;img alt="C++23" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://img.shields.io/badge/C%2B%2B-23-00599C?logo=cplusplus"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Discord Rich Presence daemon for Visual Novels on Linux. Detects games launched via &lt;strong&gt;Lutris&lt;/strong&gt; or &lt;strong&gt;Steam&lt;/strong&gt;, looks them up on &lt;a class="link" href="https://vndb.org" target="_blank" rel="noopener"
 &gt;VNDB&lt;/a&gt;, and shows the title, cover art, and total playtime in your Discord status.&lt;/p&gt;
&lt;h3 id="voice-channel"&gt;&lt;a href="#voice-channel" class="header-anchor"&gt;&lt;/a&gt;Voice channel
&lt;/h3&gt;&lt;p&gt;&lt;img alt="Voice channel presence with cover" class="gallery-image" data-flex-basis="406px" data-flex-grow="169" height="164" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://jayng9663.github.io/blog/p/vn-presence/voice_with_cover.png" width="278"&gt; &lt;img alt="Voice channel presence without cover" class="gallery-image" data-flex-basis="418px" data-flex-grow="174" height="156" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://jayng9663.github.io/blog/p/vn-presence/voice_no_cover.png" width="272"&gt;&lt;/p&gt;
&lt;h3 id="user-activity"&gt;&lt;a href="#user-activity" class="header-anchor"&gt;&lt;/a&gt;User activity
&lt;/h3&gt;&lt;p&gt;&lt;img alt="User activity with cover" class="gallery-image" data-flex-basis="273px" data-flex-grow="114" height="398" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://jayng9663.github.io/blog/p/vn-presence/activity_with_cover.png" width="454"&gt; &lt;img alt="User activity without cover" class="gallery-image" data-flex-basis="254px" data-flex-grow="105" height="424" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://jayng9663.github.io/blog/p/vn-presence/activity_no_cover.png" width="449"&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="features"&gt;&lt;a href="#features" class="header-anchor"&gt;&lt;/a&gt;Features
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Detects games from &lt;strong&gt;Lutris&lt;/strong&gt; (exact name from wrapper) and &lt;strong&gt;Steam&lt;/strong&gt; (AppID → ACF → store name)&lt;/li&gt;
&lt;li&gt;Fuzzy title matching against VNDB using trigram similarity + full-width character normalisation&lt;/li&gt;
&lt;li&gt;Fallback: searches the &lt;strong&gt;release&lt;/strong&gt; endpoint and follows the relation back to the parent VN&lt;/li&gt;
&lt;li&gt;Suppresses explicit cover images (sexual ≥ 1.80 or violence ≥ 1.80) — title still shows&lt;/li&gt;
&lt;li&gt;Playtime from &lt;strong&gt;Lutris DB&lt;/strong&gt; (&lt;code&gt;pga.db&lt;/code&gt;) or &lt;strong&gt;Steam VDF&lt;/strong&gt; (&lt;code&gt;localconfig.vdf&lt;/code&gt;) — no API key needed&lt;/li&gt;
&lt;li&gt;Discord elapsed timer reflects &lt;strong&gt;total hours played&lt;/strong&gt;, not just this session&lt;/li&gt;
&lt;li&gt;Editable &lt;code&gt;cache.csv&lt;/code&gt; for aliases, hard-links, and SKIP entries — reloaded live while running&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ignore.txt&lt;/code&gt; with exact-match for short entries (&amp;lt; 4 chars) to prevent false positives like &lt;code&gt;sh&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id="how-it-works"&gt;&lt;a href="#how-it-works" class="header-anchor"&gt;&lt;/a&gt;How it works
&lt;/h2&gt;&lt;h3 id="main-loop"&gt;&lt;a href="#main-loop" class="header-anchor"&gt;&lt;/a&gt;Main loop
&lt;/h3&gt;&lt;p&gt;Every 5 seconds the daemon runs detection, debounces the result, checks the cache, queries VNDB if needed, and updates Discord.&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart LR
 A[Detection\nLutris or Steam] --&gt; B[Debounce\nstable 2 polls]
 B --&gt; C{Cache\nlookup}
 C -- hit + fresh --&gt; E[Discord RPC]
 C -- hit + expired --&gt; D[VNDB search]
 C -- miss --&gt; D
 D --&gt; E&lt;/pre&gt;&lt;hr&gt;
&lt;h3 id="detection"&gt;&lt;a href="#detection" class="header-anchor"&gt;&lt;/a&gt;Detection
&lt;/h3&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TD
 P[Scan /proc every 5s]
 P --&gt; L{lutris-wrapper\nin cmdline?}
 L -- yes --&gt; LN[Game name from\nwrapper args]
 L -- no --&gt; S{SteamAppId\nin environ?}
 S -- yes --&gt; SA[Read appmanifest_ID.acf\nfrom all library paths]
 SA --&gt; SN[Steam store name]
 S -- no --&gt; NONE[Nothing detected]
 LN --&gt; ST[Read starttime\nfrom /proc/pid/stat field 22]
 SN --&gt; ST
 ST --&gt; SORT[Sort candidates\nby starttime ascending]&lt;/pre&gt;&lt;p&gt;Lutris passes the game name explicitly as command-line arguments after &lt;code&gt;lutris-wrapper&lt;/code&gt;, so the name is always exact. Steam injects &lt;code&gt;SteamAppId&lt;/code&gt; as an environment variable into every game process — the daemon reads it from &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/environ&lt;/code&gt;, then finds the matching &lt;code&gt;.acf&lt;/code&gt; file across all Steam library paths (including custom drives read from &lt;code&gt;libraryfolders.vdf&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;After all candidates are collected, the daemon reads &lt;strong&gt;field 22&lt;/strong&gt; (&lt;code&gt;starttime&lt;/code&gt;) from each process&amp;rsquo;s &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/stat&lt;/code&gt;. Candidates are then &lt;strong&gt;sorted ascending by starttime&lt;/strong&gt;, so the process that launched first is always tried first during VNDB resolution. This makes multi-candidate priority deterministic and reproducible across polls.&lt;/p&gt;
&lt;blockquote class="alert alert-note"&gt;
 &lt;div class="alert-header"&gt;
 &lt;span class="alert-icon"&gt;📝&lt;/span&gt;
 &lt;span class="alert-title"&gt;Note&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="alert-body"&gt;
 &lt;p&gt;See the &lt;a class="link" href="https://jayng9663.github.io/blog/p/proc/pid/stat-field-reference/" &gt;proc/[PID]/stat field reference&lt;/a&gt; for a full breakdown of all stat fields.&lt;/p&gt;
 &lt;/div&gt;
 &lt;/blockquote&gt;
&lt;blockquote class="alert alert-tip"&gt;
 &lt;div class="alert-header"&gt;
 &lt;span class="alert-icon"&gt;💡&lt;/span&gt;
 &lt;span class="alert-title"&gt;Tip&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="alert-body"&gt;
 &lt;p&gt;Run with &lt;code&gt;--verbose&lt;/code&gt; to see candidates list in the debug output:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[DEBUG] src/main.cpp:73 4 game candidate(s) found:
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEBUG] src/main.cpp:75 [lutris] pid=2037324 name=&amp;#34;終ノ空 remake&amp;#34; starttime(clock ticks)=4906595
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEBUG] src/main.cpp:75 [lutris] pid=2086738 name=&amp;#34;X-Plane 12&amp;#34; starttime(clock ticks)=4906701
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEBUG] src/main.cpp:75 [steam-appid] pid=2037822 name=&amp;#34;心象天儀本線 ~Per aspera ad astra~ Demo&amp;#34; starttime(clock ticks)=4906857
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; [DEBUG] src/main.cpp:75 [lutris] pid=2038526 name=&amp;#34;サクラノ詩－櫻の森の上を舞う－&amp;#34; starttime(clock ticks)=4907260
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
 &lt;/div&gt;
 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h3 id="vndb-resolution"&gt;&lt;a href="#vndb-resolution" class="header-anchor"&gt;&lt;/a&gt;VNDB resolution
&lt;/h3&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TD
 Q[Search query] --&gt; VN[POST /kana/vn]
 VN --&gt; SIM{Trigram similarity\n≥ 0.35 OR substring match?}
 SIM -- yes --&gt; MATCH[VnInfo returned]
 SIM -- no --&gt; REL[POST /kana/release]
 REL --&gt; FOUND{Release found?}
 FOUND -- yes --&gt; ID[Fetch parent VN\nby exact ID]
 ID --&gt; MATCH
 FOUND -- no --&gt; NOMATCH[No match\nclear presence]&lt;/pre&gt;&lt;p&gt;Before the similarity check, full-width ASCII (&lt;code&gt;！２→!2&lt;/code&gt;, &lt;code&gt;（→(&lt;/code&gt;) is normalised to half-width so Japanese game names from Lutris match VNDB&amp;rsquo;s stored titles. There is also a substring boost — if the query appears inside the returned title, the score is raised to at least 0.6, handling cases where the detected name is a short prefix of a long VNDB title.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id="cache-ttl"&gt;&lt;a href="#cache-ttl" class="header-anchor"&gt;&lt;/a&gt;Cache TTL
&lt;/h3&gt;&lt;p&gt;VNDB results are stored persistently in &lt;code&gt;cache.csv&lt;/code&gt;. On each cache hit the daemon compares the entry&amp;rsquo;s &lt;code&gt;cached_at&lt;/code&gt; timestamp against &lt;code&gt;VNDB_CACHE_TTL&lt;/code&gt;. If the entry is older than the TTL, it is treated as expired and a fresh VNDB query is issued, updating the stored data and timestamp.&lt;/p&gt;
&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TD
 HIT[Cache hit] --&gt; AGE{age &gt; VNDB_CACHE_TTL?}
 AGE -- no --&gt; USE[Use cached VnInfo]
 AGE -- yes --&gt; REQUERY[Re-query VNDB\nupdate cache.csv]
 REQUERY --&gt; USE&lt;/pre&gt;&lt;p&gt;This means ratings, cover images, and release dates in the cache are automatically refreshed over time without any manual intervention. The log line when a re-query fires looks like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;[INFO] Cache expired for &amp;#34;...&amp;#34; age=1442min/1440min — re-querying VNDB
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;h3 id="playtime--discord-elapsed-timer"&gt;&lt;a href="#playtime--discord-elapsed-timer" class="header-anchor"&gt;&lt;/a&gt;Playtime → Discord elapsed timer
&lt;/h3&gt;&lt;pre class="mermaid" style="visibility:hidden"&gt;flowchart TD
 SRC{Source?}
 SRC -- lutris --&gt; LDB[Lutris DB\npga.db · hours]
 SRC -- steam-appid --&gt; VDF[Steam VDF\nlocalconfig.vdf · minutes]
 LDB --&gt; PT[playtime in seconds]
 VDF --&gt; PT
 PT --&gt; TS[start_ts = now − playtime]
 TS --&gt; DISC[Discord: elapsed timer\ncounts up from start_ts]&lt;/pre&gt;&lt;hr&gt;
&lt;h3 id="cache-file-cachecsv--cachedb"&gt;&lt;a href="#cache-file-cachecsv--cachedb" class="header-anchor"&gt;&lt;/a&gt;Cache file (&lt;code&gt;cache.csv&lt;/code&gt; / &lt;code&gt;cache.db&lt;/code&gt;)
&lt;/h3&gt;&lt;p&gt;Located at &lt;code&gt;~/.config/vn-discord-rpc/cache.csv&lt;/code&gt; (default) or &lt;code&gt;cache.db&lt;/code&gt; when &lt;code&gt;CACHE_USE_DB = true&lt;/code&gt;. Reloaded automatically whenever the file changes on disk.&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Column&lt;/th&gt;
 &lt;th&gt;Purpose&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;key&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Detected Visual Novels name (the search term)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;alias&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Redirect this key to a different search term&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;vndb_id&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;v562&lt;/code&gt;, &lt;code&gt;v67&lt;/code&gt;, &lt;code&gt;SKIP&lt;/code&gt;, or empty&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;title&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Romanised VNDB title (auto-filled)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;alt_title&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Original script title, e.g. Japanese (auto-filled)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;image_url&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Cover image URL (auto-filled, blank if explicit(sexual or violence))&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;image_sexual&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;VNDB sexual rating 0–2 (auto-filled)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;image_violence&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;VNDB violence rating 0–2 (auto-filled)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;rating&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;VNDB community rating 0–100 (auto-filled)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;released&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Release date (auto-filled)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;cached_at&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Unix timestamp of last write (auto-filled)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;span class="lnt"&gt;6
&lt;/span&gt;&lt;span class="lnt"&gt;7
&lt;/span&gt;&lt;span class="lnt"&gt;8
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csv" data-lang="csv"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# Alias — fix wrong or garbled detection&lt;/span&gt;&lt;span class="p"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;Nice boat!&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;School Days&lt;/span&gt;&lt;span class="p"&gt;,,,,,,,,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# Skip — suppress presence for this title&lt;/span&gt;&lt;span class="p"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;妹ぱらだいす！２&lt;/span&gt;&lt;span class="p"&gt;,,&lt;/span&gt;&lt;span class="s"&gt;SKIP&lt;/span&gt;&lt;span class="p"&gt;,,,,,,,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;# Hard-link — bypass VNDB query&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt; point directly to an entry&lt;/span&gt;&lt;span class="p"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="s"&gt;My VN Title&lt;/span&gt;&lt;span class="p"&gt;,,&lt;/span&gt;&lt;span class="s"&gt;v67&lt;/span&gt;&lt;span class="p"&gt;,,,,,,,
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;hr&gt;
&lt;h3 id="ignore-list-ignoretxt"&gt;&lt;a href="#ignore-list-ignoretxt" class="header-anchor"&gt;&lt;/a&gt;Ignore list (&lt;code&gt;ignore.txt&lt;/code&gt;)
&lt;/h3&gt;&lt;p&gt;Located at &lt;code&gt;~/.config/vn-discord-rpc/ignore.txt&lt;/code&gt;. One entry per line, &lt;code&gt;#&lt;/code&gt; for comments. Reloaded automatically while running.&lt;/p&gt;
&lt;p&gt;Matching rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Entry &lt;strong&gt;&amp;lt; 4 characters&lt;/strong&gt;: exact match (case-insensitive) — (ie. prevents &lt;code&gt;sh&lt;/code&gt; matching &lt;code&gt;Higurashi&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Entry &lt;strong&gt;≥ 4 characters&lt;/strong&gt;: case-insensitive substring match&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The default file includes common false-positives: Steam runtimes, Proton, Wine helpers, and launchers.&lt;/p&gt;
&lt;blockquote class="alert alert-warning"&gt;
 &lt;div class="alert-header"&gt;
 &lt;span class="alert-icon"&gt;⚠️&lt;/span&gt;
 &lt;span class="alert-title"&gt;Warning&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="alert-body"&gt;
 &lt;p&gt;If a title has no VNDB match and is not in the ignore list, the daemon will not add it
to ignore automatically. It will retry the VNDB query on every detection. Add a &lt;code&gt;SKIP&lt;/code&gt;
entry in &lt;code&gt;cache.csv&lt;/code&gt; or an entry in &lt;code&gt;ignore.txt&lt;/code&gt; to suppress it permanently.&lt;/p&gt;
 &lt;/div&gt;
 &lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id="configuration-srcconfighpp"&gt;&lt;a href="#configuration-srcconfighpp" class="header-anchor"&gt;&lt;/a&gt;Configuration (&lt;code&gt;src/config.hpp&lt;/code&gt;)
&lt;/h2&gt;&lt;blockquote class="alert alert-caution"&gt;
 &lt;div class="alert-header"&gt;
 &lt;span class="alert-icon"&gt;🚨&lt;/span&gt;
 &lt;span class="alert-title"&gt;Caution&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="alert-body"&gt;
 &lt;p&gt;Be caution on changing &lt;code&gt;IMAGE_SEXUAL&lt;/code&gt; and &lt;code&gt;IMAGE_VIOLENCE&lt;/code&gt; thresholds in &lt;code&gt;src/config.hpp&lt;/code&gt;.
Those thresholds are set to &lt;code&gt;1.80&lt;/code&gt; (slightly below VNDB&amp;rsquo;s &lt;strong&gt;Explicit&lt;/strong&gt; level of &lt;code&gt;2.00&lt;/code&gt;)
because VNDB image ratings are user-reported and may be underrated by a small margin —
the 0.20 buffer ensures borderline explicit covers are still suppressed.
Raising the threshold above &lt;code&gt;2.00&lt;/code&gt; would cause explicit (pornographic) cover art to appear
in your Discord status, visible to everyone on your friends list. Displaying explicit
content in Discord Rich Presence may violates &lt;a class="link" href="https://discord.com/terms" target="_blank" rel="noopener"
 &gt;Discord&amp;rsquo;s Terms of Service&lt;/a&gt;
and &lt;strong&gt;may result in a permanent account ban&lt;/strong&gt;.&lt;/p&gt;
 &lt;/div&gt;
 &lt;/blockquote&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Constant&lt;/th&gt;
 &lt;th&gt;Default&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;DISCORD_APP_ID&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;1482345564698841189&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Discord application ID&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;DISCORD_ACTIVITY_TYPE&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Activity type: 0=Game, 1=Streaming, 2=Listening, 3=Watching&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;IMAGE_SEXUAL&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;1.80&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Maximum sexual rating before cover is suppressed&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;IMAGE_VIOLENCE&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;1.80&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Maximum violence rating before cover is suppressed&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;IMAGE_VOTECOUNT&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;5&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Minimum vote count before ratings are trusted&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;VNDB_MIN_SIMILARITY&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0.35&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Minimum trigram score to accept a VNDB match&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;POLL_INTERVAL&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;5s&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;How often to scan &lt;code&gt;/proc&lt;/code&gt; for running processes&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;VNDB_CACHE_TTL&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;24h&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;How long a cache entry is valid before re-querying VNDB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;STABLE_TITLE_POLLS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Polls a candidate must be stable before acting&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;VNDB_MAX_RESULTS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;1&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Maximum results per VNDB query (index 0 is used)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;CACHE_USE_DB&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Use SQLite (&lt;code&gt;cache.db&lt;/code&gt;) instead of CSV &lt;em&gt;(experimental)&lt;/em&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;RPC_STATE_READING&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;&amp;quot;Reading&amp;quot;&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Discord state string while a VN is active&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;RPC_STATE_IDLE&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;&amp;quot;Idle&amp;quot;&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Discord state string while idle&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;RPC_DEFAULT_DETAILS&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;&amp;quot;Playing a Visual Novel&amp;quot;&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Details line when no VNDB match is found&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;RPC_SMALL_IMG_KEY&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;&amp;quot;vndb_logo&amp;quot;&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Discord asset key for the small VNDB logo image&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;RPC_SMALL_IMG_TEXT&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;&amp;quot;VNDB&amp;quot;&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Tooltip text for the small image&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="architecture"&gt;&lt;a href="#architecture" class="header-anchor"&gt;&lt;/a&gt;Architecture
&lt;/h2&gt;&lt;p&gt;The project is composed of nine focused, single-responsibility modules:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Module&lt;/th&gt;
 &lt;th&gt;Source Files&lt;/th&gt;
 &lt;th&gt;Responsibility&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Entry point&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;main.cpp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Main loop, debounce state machine, candidate resolution pipeline&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Process scanner&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;process_scanner.cpp/.hpp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Iterates &lt;code&gt;/proc&lt;/code&gt;, detects Lutris and Steam game processes, reads &lt;code&gt;starttime&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Steam detector&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;steam_detector.cpp/.hpp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Reads &lt;code&gt;SteamAppId&lt;/code&gt; env vars, parses ACF manifests and VDF playtime files&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;VNDB client&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;vndb_client.cpp/.hpp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;HTTP POST to VNDB Kana API, trigram matching, release endpoint fallback&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;VN cache&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;vn_cache.cpp/.hpp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Persistent CSV/SQLite cache with alias, SKIP, TTL, and live-reload logic&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Ignore list&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ignore_list.cpp/.hpp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Live-reloadable process-name suppression list with exact/substring rules&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;RPC manager&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;rpc_manager.cpp/.hpp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Discord IPC wrapper with rate limiting, deferred flush, and change detection&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Config&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;config.hpp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;All compile-time constants in one place&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Logger&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;logger.hpp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Thread-safe ANSI-coloured logger singleton with &lt;code&gt;LOG_DEBUG/INFO/WARN/ERR&lt;/code&gt; macros&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;strong&gt;Lutris DB&lt;/strong&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;lutris_db.cpp/.hpp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Reads and formats playtime from Lutris&amp;rsquo;s SQLite &lt;code&gt;pga.db&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id="key-design-decisions"&gt;&lt;a href="#key-design-decisions" class="header-anchor"&gt;&lt;/a&gt;Key Design Decisions
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;Deterministic multi-candidate priority&lt;/strong&gt; — when multiple games are running, candidates are sorted by &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/stat&lt;/code&gt; field 22 (&lt;code&gt;starttime&lt;/code&gt;, clock ticks since boot). The process that launched earliest is always tried first, making priority stable and reproducible across polls without any user configuration.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Discord rate-limit compliance&lt;/strong&gt; — Discord silently drops &lt;code&gt;SET_ACTIVITY&lt;/code&gt; calls faster than ~15 seconds apart. &lt;code&gt;RpcManager&lt;/code&gt; tracks the wall-clock time of the last successful push and defers any call that falls within a 16-second window. Deferred updates are flushed on the next &lt;code&gt;runCallbacks()&lt;/code&gt; tick, ensuring no update is ever lost.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;No presence flicker on stable sessions&lt;/strong&gt; — the early-out in the main loop checks whether the currently displayed VN is still in the candidate set before doing any cache or VNDB work. If it is still running, the loop sleeps immediately, so Discord is never unnecessarily cleared and re-set.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Cache-first, ignore-list-second&lt;/strong&gt; — VNDB HTTP queries are only issued on a true cache miss or TTL expiry. Candidates that fail VNDB resolution are added to the ignore list so subsequent polls skip them instantly, letting the next candidate be tried without any network round trip.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Live file reloading without restart&lt;/strong&gt; — both &lt;code&gt;cache.csv&lt;/code&gt; and &lt;code&gt;ignore.txt&lt;/code&gt; are checked for &lt;code&gt;mtime&lt;/code&gt; changes on every poll using &lt;code&gt;std::filesystem::last_write_time&lt;/code&gt;. Edits made while the daemon is running take effect within one poll cycle with no signals or process restart needed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Explicit content safety&lt;/strong&gt; — image ratings are only trusted when backed by at least &lt;code&gt;IMAGE_VOTECOUNT&lt;/code&gt; votes. Cover URLs are stripped from cache entries for explicit results so they can never accidentally appear after a cache reload even if thresholds are later changed.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="building"&gt;&lt;a href="#building" class="header-anchor"&gt;&lt;/a&gt;Building
&lt;/h2&gt;&lt;blockquote class="alert alert-important"&gt;
 &lt;div class="alert-header"&gt;
 &lt;span class="alert-icon"&gt;📌&lt;/span&gt;
 &lt;span class="alert-title"&gt;Important&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="alert-body"&gt;
 &lt;p&gt;Initialise submodules before building — the two header-only dependencies are not
downloaded automatically.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git submodule update --init --recursive
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
 &lt;/div&gt;
 &lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cmake -B build -DCMAKE_BUILD_TYPE&lt;span class="o"&gt;=&lt;/span&gt;Release
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;cmake --build build
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="dependencies"&gt;&lt;a href="#dependencies" class="header-anchor"&gt;&lt;/a&gt;Dependencies
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;Library&lt;/th&gt;
 &lt;th&gt;Purpose&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a class="link" href="https://github.com/EclipseMenu/discord-presence" target="_blank" rel="noopener"
 &gt;discord-presence&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Discord Rich Presence (modern C++ rewrite)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a class="link" href="https://github.com/nlohmann/json" target="_blank" rel="noopener"
 &gt;nlohmann/json&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;JSON parsing&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a class="link" href="https://curl.se/libcurl/" target="_blank" rel="noopener"
 &gt;libcurl&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;HTTP requests to VNDB API&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;a class="link" href="https://www.sqlite.org/" target="_blank" rel="noopener"
 &gt;libsqlite3&lt;/a&gt;&lt;/td&gt;
 &lt;td&gt;Read Lutris playtime database&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id="usage"&gt;&lt;a href="#usage" class="header-anchor"&gt;&lt;/a&gt;Usage
&lt;/h2&gt;&lt;blockquote class="alert alert-tip"&gt;
 &lt;div class="alert-header"&gt;
 &lt;span class="alert-icon"&gt;💡&lt;/span&gt;
 &lt;span class="alert-title"&gt;Tip&lt;/span&gt;
 &lt;/div&gt;
 &lt;div class="alert-body"&gt;
 &lt;p&gt;Run with &lt;code&gt;--verbose&lt;/code&gt; if a title is not being detected or matched — the debug output shows
exactly which process was found, what VNDB returned, and the similarity score.&lt;/p&gt;
 &lt;/div&gt;
 &lt;/blockquote&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./vn-discord-rpc &lt;span class="c1"&gt;# normal&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./vn-discord-rpc --verbose &lt;span class="c1"&gt;# debug logging&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;./vn-discord-rpc --help
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Launch a game through &lt;strong&gt;Lutris&lt;/strong&gt; or &lt;strong&gt;Steam&lt;/strong&gt;, and the daemon will detect it automatically. Press &lt;code&gt;Ctrl+C&lt;/code&gt; to quit cleanly.&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id="file-locations"&gt;&lt;a href="#file-locations" class="header-anchor"&gt;&lt;/a&gt;File locations
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;File&lt;/th&gt;
 &lt;th&gt;Path&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;Cache (CSV)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;~/.config/vn-discord-rpc/cache.csv&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Cache (SQLite, experimental)&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;~/.config/vn-discord-rpc/cache.db&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Ignore list&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;~/.config/vn-discord-rpc/ignore.txt&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Lutris DB&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;~/.local/share/lutris/pga.db&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;Steam VDF&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;~/.local/share/Steam/userdata/&amp;lt;id&amp;gt;/config/localconfig.vdf&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;</description></item><item><title>/proc/[PID]/stat Field Reference</title><link>https://jayng9663.github.io/blog/p/proc/pid/stat-field-reference/</link><pubDate>Sun, 29 Mar 2026 23:08:22 -0700</pubDate><guid>https://jayng9663.github.io/blog/p/proc/pid/stat-field-reference/</guid><description>&lt;p&gt;The &lt;code&gt;/proc/[PID]/stat&lt;/code&gt; file exposes process status information. Each field is listed below in order of appearance.&lt;/p&gt;
&lt;h2 id="fields"&gt;&lt;a href="#fields" class="header-anchor"&gt;&lt;/a&gt;Fields
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;ID&lt;/th&gt;
 &lt;th&gt;Field&lt;/th&gt;
 &lt;th&gt;Description&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pid&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Process ID&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;tcomm&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Filename of the executable&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;state&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Process state: &lt;code&gt;R&lt;/code&gt; running, &lt;code&gt;S&lt;/code&gt; sleeping, &lt;code&gt;D&lt;/code&gt; uninterruptible sleep, &lt;code&gt;Z&lt;/code&gt; zombie, &lt;code&gt;T&lt;/code&gt; traced or stopped&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ppid&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Process ID of the parent process&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;5&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pgrp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Process group ID&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;6&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;sid&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Session ID&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;7&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;tty_nr&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;TTY the process uses&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;8&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;tty_pgrp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Process group ID of the TTY&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;9&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;flags&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Task flags&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;10&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;min_flt&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Number of minor faults&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;11&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;cmin_flt&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Number of minor faults including children&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;12&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;maj_flt&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Number of major faults&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;13&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;cmaj_flt&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Number of major faults including children&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;14&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;utime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;User mode jiffies&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;15&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;stime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Kernel mode jiffies&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;16&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;cutime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;User mode jiffies including children&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;17&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;cstime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Kernel mode jiffies including children&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;18&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;priority&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Priority level&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;19&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;nice&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Nice level&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;20&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;num_threads&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Number of threads&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;21&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;it_real_value&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;(Obsolete, always 0)&lt;/em&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;22&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;start_time&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Time the process started after system boot&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;23&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;vsize&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Virtual memory size&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;24&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;rss&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Resident set memory size&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;25&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;rsslim&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Current limit in bytes on the RSS&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;26&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;start_code&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Address above which program text can run&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;27&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;end_code&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Address below which program text can run&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;28&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;start_stack&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Address of the start of the main process stack&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;29&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;esp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Current value of ESP&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;30&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;eip&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Current value of EIP&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;31&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pending&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Bitmap of pending signals&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;32&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;blocked&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Bitmap of blocked signals&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;33&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;sigign&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Bitmap of ignored signals&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;34&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;sigcatch&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Bitmap of caught signals&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;35&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;(placeholder)&lt;/em&gt;&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;(Was wchan address — use &lt;code&gt;/proc/[PID]/wchan&lt;/code&gt; instead)&lt;/em&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;36&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;(placeholder)&lt;/em&gt;&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;(Reserved)&lt;/em&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;37&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;(placeholder)&lt;/em&gt;&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;(Reserved)&lt;/em&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;38&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;exit_signal&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Signal sent to the parent thread on exit&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;39&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;task_cpu&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;CPU the task is scheduled on&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;40&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;rt_priority&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Realtime priority&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;41&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;policy&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Scheduling policy (see &lt;code&gt;man sched_setscheduler&lt;/code&gt;)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;42&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;blkio_ticks&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Time spent waiting for block I/O&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;43&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;gtime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Guest time of the task in jiffies&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;44&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;cgtime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Guest time of child tasks in jiffies&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;45&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;start_data&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Address above which program data+BSS is placed&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;46&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;end_data&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Address below which program data+BSS is placed&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;47&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;start_brk&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Address above which the heap can be expanded with &lt;code&gt;brk()&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;48&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;arg_start&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Address above which the command line is placed&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;49&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;arg_end&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Address below which the command line is placed&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;50&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;env_start&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Address above which the environment is placed&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;51&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;env_end&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Address below which the environment is placed&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;52&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;exit_code&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Thread exit code as reported by &lt;code&gt;waitpid&lt;/code&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="example"&gt;&lt;a href="#example" class="header-anchor"&gt;&lt;/a&gt;Example
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;871869 (VN-Presence) S 12198 871869 12198 34830 871869 4194560 1205 0 173 0 46734 8492 0 0 20 0 2 0 10523393 176685056 2837 18446744073709551615 94266814361600 94266814993397 140734575381584 0 0 0 0 0 16386 0 0 0 17 16 0 0 0 0 0 94266815325280 94266815330208 94267110821888 140734575389833 140734575389847 140734575389847 140734575394794 0
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Parsed field by field:&lt;/p&gt;
&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;ID&lt;/th&gt;
 &lt;th&gt;Field&lt;/th&gt;
 &lt;th&gt;Value&lt;/th&gt;
 &lt;th&gt;Notes&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;1&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pid&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;871869&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Process ID&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;2&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;tcomm&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;(VN-Presence)&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Executable name&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;3&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;state&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;S&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Sleeping (interruptible)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;4&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;ppid&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;12198&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Parent PID&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;5&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pgrp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;871869&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Process group ID&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;6&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;sid&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;12198&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Session ID&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;7&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;tty_nr&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;34830&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;TTY device number&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;8&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;tty_pgrp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;871869&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Foreground process group of TTY&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;9&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;flags&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;4194560&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Task flags&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;10&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;min_flt&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;1205&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Minor page faults&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;11&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;cmin_flt&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Minor faults including children&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;12&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;maj_flt&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;173&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Major page faults&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;13&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;cmaj_flt&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Major faults including children&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;14&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;utime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;46734&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;User-mode CPU time (jiffies) — ~467s at 100 Hz&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;15&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;stime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;8492&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Kernel-mode CPU time (jiffies) — ~84s at 100 Hz&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;16&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;cutime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Children user-mode jiffies&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;17&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;cstime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Children kernel-mode jiffies&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;18&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;priority&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;20&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Kernel priority&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;19&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;nice&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Nice value (0 = default)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;20&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;num_threads&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;2&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Thread count&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;21&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;it_real_value&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Obsolete, always 0&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;22&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;start_time&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;10523393&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Jiffies after boot when process started&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;23&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;vsize&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;176685056&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Virtual memory size (168 MiB)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;24&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;rss&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;2837&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Resident set size (pages) — 2837 × 4 KiB ≈ 11 MiB&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;25&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;rsslim&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;18446744073709551615&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;RSS limit (0xFFFFFFFFFFFFFFFF = unlimited)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;26&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;start_code&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;94266814361600&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Start of executable text segment&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;27&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;end_code&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;94266814993397&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;End of executable text segment&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;28&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;start_stack&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;140734575381584&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Stack start address&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;29&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;esp&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Current stack pointer&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;30&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;eip&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Current instruction pointer&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;31&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;pending&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Pending signals bitmap&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;32&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;blocked&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Blocked signals bitmap&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;33&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;sigign&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;16386&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Ignored signals bitmap&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;34&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;sigcatch&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Caught signals bitmap&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;35&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;(placeholder)&lt;/em&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;(Was wchan)&lt;/em&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;36&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;(placeholder)&lt;/em&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;(Reserved)&lt;/em&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;37&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;(placeholder)&lt;/em&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;em&gt;(Reserved)&lt;/em&gt;&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;38&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;exit_signal&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;17&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Signal sent to parent on exit (17 = SIGCHLD)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;39&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;task_cpu&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;16&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Last CPU the task ran on&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;40&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;rt_priority&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Realtime priority (0 = not realtime)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;41&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;policy&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Scheduling policy (0 = SCHED_NORMAL)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;42&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;blkio_ticks&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Block I/O wait ticks&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;43&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;gtime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Guest time (jiffies)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;44&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;cgtime&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Children guest time (jiffies)&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;45&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;start_data&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;94266815325280&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Start of data+BSS segment&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;46&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;end_data&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;94266815330208&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;End of data+BSS segment&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;47&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;start_brk&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;94267110821888&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Start of heap&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;48&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;arg_start&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;140734575389833&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Start of command-line args&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;49&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;arg_end&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;140734575389847&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;End of command-line args&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;50&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;env_start&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;140734575389847&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Start of environment&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;51&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;env_end&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;140734575394794&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;End of environment&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;52&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;exit_code&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;&lt;code&gt;0&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;Exit code&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id="notes"&gt;&lt;a href="#notes" class="header-anchor"&gt;&lt;/a&gt;Notes
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;Fields are space-separated and appear in the order listed above.&lt;/li&gt;
&lt;li&gt;Time values (&lt;code&gt;utime&lt;/code&gt;, &lt;code&gt;stime&lt;/code&gt;, etc.) are measured in &lt;strong&gt;jiffies&lt;/strong&gt; (clock ticks). Divide by &lt;code&gt;sysconf(_SC_CLK_TCK)&lt;/code&gt; to convert to seconds.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="references"&gt;&lt;a href="#references" class="header-anchor"&gt;&lt;/a&gt;References
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;The /proc Filesystem&lt;/code&gt; &lt;a class="link" href="https://www.kernel.org/doc/html/latest/filesystems/proc.html#id12" target="_blank" rel="noopener"
 &gt;linux kernel doc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Linux kernel source: &lt;code&gt;fs/proc/array.c&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item><item><title>心象天儀本線 ~Per Aspera Ad Astra~ Demo</title><link>https://jayng9663.github.io/blog/p/%E5%BF%83%E8%B1%A1%E5%A4%A9%E5%84%80%E6%9C%AC%E7%B7%9A-~per-aspera-ad-astra~-demo/</link><pubDate>Sun, 29 Mar 2026 21:23:52 -0700</pubDate><guid>https://jayng9663.github.io/blog/p/%E5%BF%83%E8%B1%A1%E5%A4%A9%E5%84%80%E6%9C%AC%E7%B7%9A-~per-aspera-ad-astra~-demo/</guid><description>&lt;img src="https://jayng9663.github.io/blog/" alt="Featured image of post 心象天儀本線 ~Per Aspera Ad Astra~ Demo" /&gt;&lt;p&gt;&lt;img class="gallery-image" data-flex-basis="455px" data-flex-grow="189" height="1000" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://jayng9663.github.io/blog/p/%E5%BF%83%E8%B1%A1%E5%A4%A9%E5%84%80%E6%9C%AC%E7%B7%9A-~per-aspera-ad-astra~-demo/1.png" srcset="https://jayng9663.github.io/blog/p/%E5%BF%83%E8%B1%A1%E5%A4%A9%E5%84%80%E6%9C%AC%E7%B7%9A-~per-aspera-ad-astra~-demo/1_hu_e8bf163f3f3b13ab.png 800w, https://jayng9663.github.io/blog/p/%E5%BF%83%E8%B1%A1%E5%A4%A9%E5%84%80%E6%9C%AC%E7%B7%9A-~per-aspera-ad-astra~-demo/1_hu_5677f961f7dae0f5.png 1600w, https://jayng9663.github.io/blog/p/%E5%BF%83%E8%B1%A1%E5%A4%A9%E5%84%80%E6%9C%AC%E7%B7%9A-~per-aspera-ad-astra~-demo/1.png 1897w" width="1897"&gt;&lt;/p&gt;
&lt;p&gt;Title: 心象天儀本線 ~per aspera ad astra~&lt;br/&gt;
Developer: Atelier Ueshima Erika&lt;br/&gt;
VNDB: &lt;a class="link" href="https://vndb.org/v54933" target="_blank" rel="noopener"
 &gt;https://vndb.org/v54933&lt;/a&gt;&lt;br/&gt;
Official Website: &lt;a class="link" href="https://www.hoshiorigakuen.com/" target="_blank" rel="noopener"
 &gt;https://www.hoshiorigakuen.com/&lt;/a&gt;&lt;br/&gt;
Steam: &lt;a class="link" href="https://store.steampowered.com/app/3664060/" target="_blank" rel="noopener"
 &gt;https://store.steampowered.com/app/3664060/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Demo release for the doujin visual novel &lt;em&gt;心象天儀本線 ~Per Aspera Ad Astra~&lt;/em&gt;, demo dropped January 29, 2026, ahead of the full release later in 2026. It caught my attention when I looking up new game on Steam, because of it uniq &lt;em&gt;doujin&lt;/em&gt; art style, 4:3 resolution and the incredibly ancient UI give it a classic visual novel feel, it reminds me of early 2000–2010 visual novels.&lt;/p&gt;
&lt;div class="video-wrapper"&gt;
 &lt;iframe loading="lazy" 
 src="https://www.youtube.com/embed/1eF3VeaXkg4" 
 allowfullscreen 
 title="YouTube Video"
 &gt;
 &lt;/iframe&gt;
&lt;/div&gt;

&lt;p&gt;It&amp;rsquo;s a debut doujin visual novel from Atelier Ueshima Erika — a small indie studio out of Taiwan, as far as I can tell — and you play as 上島椿 (Ueshima Tsubaki) &lt;span class="inline-spoiler"&gt;at the end of the demo, a mysterious girl reveals that it's actually Ueshima Tsubaki who has been talking to you — the player — all along in train&lt;/span&gt;
, a transfer student arriving at the 星織學園 (Hoshiori Academy). The story is told through what the game calls &amp;ldquo;touching tickets&amp;rdquo;: fragmented vignettes that slowly build toward something larger. A Literature Club. A galactic train. Recurring dreams. It shouldn&amp;rsquo;t cohere, and yet it does.&lt;/p&gt;
&lt;p&gt;What gets me is how intentional it all feels. The dreamlike art and surreal structure don&amp;rsquo;t come across as aesthetic choices slapped on top — they feel load-bearing, like the whole thing would collapse without them. And the soundtrack by composer 10lulu (60+ tracks planned for the full release, apparently), which I really like, its doing a lot of heavy lifting in the best possible way.&lt;/p&gt;
&lt;p&gt;The full release is planned for later in 2026, promising 7–9 hours of playtime. If the demo is fit your type, this is one to keep on your wishlist. :L&lt;br/&gt;
I will make another post once it released and I when through. :L&lt;/p&gt;</description></item></channel></rss>