Skip to content

Repository files navigation

lin0

License: BSD-2-ClauseRolling releaseDocker Pulls

 _._
e/` '\,.eo-__. lin0 (linux zero) is a
'/.' .|_/e--. '\e super minimal source
,;-o-.'|` //e e\ |` based linux meta
./' ,e0\o //-o.__. ,. \' distribution, aimed
./` /' -/e e\o_/___. \|' at power users or
e|`/`,o-o\ /v-/e_. '\. \. minimalism enthusiasts
'/ ._e._, \ // \` \e |'
'|'"/ \.V | `|' `|'|` it was born from
`|e`|' | # / `|. |`|` exercises in how
e|` ` /\- ,\ e|' '\` minimal a linux system
'` _/ / / \ ` `|' can get.
.,wW'^^^//;^-^;^;w_

Features

  • Linux kernel (no initrd)
  • musl libc
  • mksh (MirBSD Korn Shell)
  • tcc (Tiny C Compiler)
  • toybox
  • Shell-script init (init)

Quick start

git clone https://terminal.pink/lin0
cd lin0
make help# list platforms
make # build for the host architecture

Each platform is a Make target. Outputs are rootfs-<platform>.tar.gz (and a full disk image for some boards).

make x86_64
make pinebookpro
make rpizero # also: make rpizero-img
make radxacm5io # rootfs tarball + hybrid disk image

Edit configs/<platform>-*.config, etc/*, or init, then rebuild — Make only rebuilds what changed.

Images

Prebuilt tarballs live under www/. After download, verify the full SHA-256 digest so the file has not been corrupted or tampered with:

# Linux
sha256sum -c SHA256SUMS
# macOS
shasum -a 256 -c SHA256SUMS

www/SHA256SUMS has the full digests. The sha256 column below is the first 16 hex chars for a quick eyeball check. Arch-only builds have no kernel; the rest do. Raspberry Pi Zero is build-only (not published).

+----------------------+------+------------------+------------------+
| platform | size | sha256 | build |
+----------------------+------+------------------+------------------+
| x86_64 | 4.6M | d9b0345efba6d227 | make x86_64 |
| arm64 | 3.9M | a4f99c89fb6b2d97 | make arm64 |
| hp elite desk 800 g1 | 14M | 73752c23c40d1fdd | make hpelitedesk |
| pinebook pro | 14M | 3e49689772dc0235 | make pinebookpro |
| raspberry pi 3b+ | 35M | 6b859999760e0d59 | make rpi3bplus |
| rpi cm5 + io board | 51M | 06bb5b9fdda241a9 | make rpi-cm5io |
| radxa cm5 + io | 27M | 0af2d1501e4e6c82 | make radxacm5io |
| rpi zero / zero w | — | (local) | make rpizero |
+----------------------+------+------------------+------------------+

Tarballs: www/rootfs-*.tar.gz.

Docker

Prebuilt images for trying the userland or compiling with musl/tcc:

docker pull bleemayer/lin0:latest

See bleemayer/lin0 on Docker Hub. Architectures match the tarballs above.

Install from a tarball

tar -xf rootfs-ARCH.tar.gz -C /mnt/your-root
cp path/to/kernel /mnt/your-root/boot/ # if the tarball has no kernel

Replace ARCH with x86_64, arm64, or a platform name. Kernel name is platform-specific (bzImage, Image, zImage, …).

Files under pkg/ are copied to /home/root/ on the target when present.

Radxa CM5 + IO (mainline)

make radxacm5io builds a hybrid bootable disk image: SPL/U-Boot and the GPT layout come from the official Radxa Debian image; partition 3 is resized and filled with lin0 (mainline kernel + rk3588s-radxa-cm5-io.dtb).

On macOS, Make runs the arm64 compile and the privileged partition formatting inside Docker automatically.

git clone https://terminal.pink/lin0
cd lin0
make radxacm5io
OutputPurpose
lin0-radxacm5io.imgFull GPT image (loader at sector 64, ext4 root on partition 3)
rootfs-radxacm5io.tar.gzRoot filesystem (kernel + DTB under /boot)
build/rk3588_spl_loader*.binMaskrom stage-1 loader for rkdeveloptool db

Flash to eMMC (recommended)

Puts the board in Maskrom mode (hold recovery, power on), then:

rkdeveloptool ld
rkdeveloptool wl 0 lin0-radxacm5io.img
rkdeveloptool rd

This overwrites the existing Debian install.

Flash to SD (whole disk)

# Linux
sudo dd if=lin0-radxacm5io.img of=/dev/sdX bs=4M status=progress conv=fsync
# macOS — use diskutil list; example disk4
diskutil unmountDisk /dev/disk4
sudo dd if=lin0-radxacm5io.img of=/dev/rdisk4 bs=4m

Power the Radxa CM5 IO with 12 V. Console is HDMI (tty0) with a USB keyboard.

Optional knobs:

make radxacm5io RADXA_LINUXVER=master RADXA_P3_MB=128

U-Boot offers two root choices: root=/dev/mmcblk0p3 (eMMC partition 3) and root=LABEL=lin0root. Pick one from the boot menu if the default does not find the rootfs.

Build from source

  1. Add or edit kernel/toybox configs:

    configs/MODEL-linux.config
    configs/MODEL-toybox.config
    
  2. Build:

    make help
    make x86_64
    make pinebookpro
    make radxacm5io
    make # host architecture
  3. Install the resulting rootfs-*.tar.gz (or disk image) on the target.

Static system config lives in etc/ (generic only). TLS trust anchors are fetched at build time from curl.se/ca/cacert.pem into rootfs/etc/ssl/ (SHA-256 pinned as CACERT_SHA256 in the Makefile). wget links against BearSSL + libtls-bearssl and loads /etc/ssl/cert.pem by default.

Usage

  • Username:root
  • Password:lin0

There is no systemd — init is a shell script. Expect to configure the rest yourself.

Networking

Default DNS ships in etc/resolv.conf. On a running system:

vi /etc/resolv.conf

Users

lin0 ships as a single-user system (root only). Toybox useradd / adduser are not built in; add accounts by hand.

On a running system, as root:

# primary group (gid 100 is already in /etc/group as "users")echo'myuser::1000:100:myuser:/home/myuser:/bin/sh'>> /etc/passwd
mkdir -p /home/myuser
chown 1000:100 /home/myuser
passwd myuser

Then su - myuser or log in as myuser at the getty prompt.

Passwords live in /etc/passwd (there is no /etc/shadow). passwd updates that file. Use a free uid (1000+) and an existing gid from /etc/group (default users is 100). Shell must be listed in /etc/shells (default /bin/sh).

To bake a user into the image, edit etc/passwd and etc/group in the tree, create the home directory under rootfs/home/, then rebuild. Lock down root with passwd after first boot.

Extra software

Install what you need on the target (for example wpa_supplicant for Wi-Fi). lin0 is a starting point, not a full desktop stack.

Roadmap

  • Ship HP EliteDesk with firmware built into the kernel
  • Make the system able to compile itself
  • Improve the Raspberry Pi 3B+ rootfs
  • Load modules and start daemons from init
  • Better login/issue screen (something like ly)
  • Man pages
  • Add lin0 to fetch and similar tools

Site pages

The public site is the static files under www/, served from the bare repo at terminal.pink/lin0. Hand-write www/index.html. captain fills in log.html, tree.html, refs.html, and per-commit pages. It never edits index.html.

Only www/ is exported to the forge. Links that point outside that folder (for example ../docs/) 404 on the site; point at tree.html or copy the page into www/.

Index style

Match this page (and the other repos on terminal.pink):

  • 52-character <pre>, magenta links (#ff00ff), color-scheme: light dark
  • nav line: log | tree | refs
  • lowercase running text; do not indent code snippets
  • clone URL with no .git suffix: git clone https://terminal.pink/lin0

New repo on terminal.pink

Same layout as this one. Replace NAME with the project directory name.

  1. Hand-write www/index.html as above.

  2. Init and commit the tree. Skip build artifacts.

    git init -b main
    git add …
    git commit
  3. Install captain and generate pages. Generated files describe the commit they were built from, so they lag the tip by one unless you make a follow-up refresh commit (--no-verify so the hook does not dirty the tree again).

    /path/to/captain install # post-commit hook
    captain -f
    git add www
    git commit --no-verify -m "www: initial captain pages."
    captain -f
    git add www
    git commit --no-verify -m "www: refresh captain pages."
  4. Create the bare on the Pi and install the forge hooks.

    ssh pi 'cd ~/terminal.pink && git init --bare NAME'

    Copy ~/terminal.pink/captain/hooks/post-receive to NAME/hooks/post-receive. On each push to main it walks every new commit, writes www/* into the bare root (prefix stripped), and appends feed.xml. lin0’s copy of this hook also git push --mirror to GitHub; skip that line until a mirror exists.

    Servrian serves the bare directory as static files. Git’s first request is info/refs?service=git-upload-pack, which 404s unless that name exists. post-update should keep dumb HTTP working:

    #!/bin/sh
    git gc
    git update-server-info
    ln -sfn refs "info/refs?service=git-upload-pack"
  5. Push, then list the project on s.html in the terminal.pink repo.

    git remote add origin pi:terminal.pink/NAME
    git push -u origin main

    SSH clone is pi:terminal.pink/NAME. HTTPS is https://terminal.pink/NAME (no .git suffix; shallow clones are not supported over this dumb transport).

Help

Mailing list: lin0 AT terminal DOT pink

License

BSD 2-Clause. © 2023–2026 Brian Mayer

About

Mirror repository of my distro

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
GitHub - blmayer/lin0: Mirror repository of my distro · GitHub
Skip to content

Repository files navigation

lin0

License: BSD-2-ClauseRolling releaseDocker Pulls

 _._
e/` '\,.eo-__. lin0 (linux zero) is a
'/.' .|_/e--. '\e super minimal source
,;-o-.'|` //e e\ |` based linux meta
./' ,e0\o //-o.__. ,. \' distribution, aimed
./` /' -/e e\o_/___. \|' at power users or
e|`/`,o-o\ /v-/e_. '\. \. minimalism enthusiasts
'/ ._e._, \ // \` \e |'
'|'"/ \.V | `|' `|'|` it was born from
`|e`|' | # / `|. |`|` exercises in how
e|` ` /\- ,\ e|' '\` minimal a linux system
'` _/ / / \ ` `|' can get.
.,wW'^^^//;^-^;^;w_

Features

  • Linux kernel (no initrd)
  • musl libc
  • mksh (MirBSD Korn Shell)
  • tcc (Tiny C Compiler)
  • toybox
  • Shell-script init (init)

Quick start

git clone https://terminal.pink/lin0
cd lin0
make help# list platforms
make # build for the host architecture

Each platform is a Make target. Outputs are rootfs-<platform>.tar.gz (and a full disk image for some boards).

make x86_64
make pinebookpro
make rpizero # also: make rpizero-img
make radxacm5io # rootfs tarball + hybrid disk image

Edit configs/<platform>-*.config, etc/*, or init, then rebuild — Make only rebuilds what changed.

Images

Prebuilt tarballs live under www/. After download, verify the full SHA-256 digest so the file has not been corrupted or tampered with:

# Linux
sha256sum -c SHA256SUMS
# macOS
shasum -a 256 -c SHA256SUMS

www/SHA256SUMS has the full digests. The sha256 column below is the first 16 hex chars for a quick eyeball check. Arch-only builds have no kernel; the rest do. Raspberry Pi Zero is build-only (not published).

+----------------------+------+------------------+------------------+
| platform | size | sha256 | build |
+----------------------+------+------------------+------------------+
| x86_64 | 4.6M | d9b0345efba6d227 | make x86_64 |
| arm64 | 3.9M | a4f99c89fb6b2d97 | make arm64 |
| hp elite desk 800 g1 | 14M | 73752c23c40d1fdd | make hpelitedesk |
| pinebook pro | 14M | 3e49689772dc0235 | make pinebookpro |
| raspberry pi 3b+ | 35M | 6b859999760e0d59 | make rpi3bplus |
| rpi cm5 + io board | 51M | 06bb5b9fdda241a9 | make rpi-cm5io |
| radxa cm5 + io | 27M | 0af2d1501e4e6c82 | make radxacm5io |
| rpi zero / zero w | — | (local) | make rpizero |
+----------------------+------+------------------+------------------+

Tarballs: www/rootfs-*.tar.gz.

Docker

Prebuilt images for trying the userland or compiling with musl/tcc:

docker pull bleemayer/lin0:latest

See bleemayer/lin0 on Docker Hub. Architectures match the tarballs above.

Install from a tarball

tar -xf rootfs-ARCH.tar.gz -C /mnt/your-root
cp path/to/kernel /mnt/your-root/boot/ # if the tarball has no kernel

Replace ARCH with x86_64, arm64, or a platform name. Kernel name is platform-specific (bzImage, Image, zImage, …).

Files under pkg/ are copied to /home/root/ on the target when present.

Radxa CM5 + IO (mainline)

make radxacm5io builds a hybrid bootable disk image: SPL/U-Boot and the GPT layout come from the official Radxa Debian image; partition 3 is resized and filled with lin0 (mainline kernel + rk3588s-radxa-cm5-io.dtb).

On macOS, Make runs the arm64 compile and the privileged partition formatting inside Docker automatically.

git clone https://terminal.pink/lin0
cd lin0
make radxacm5io
OutputPurpose
lin0-radxacm5io.imgFull GPT image (loader at sector 64, ext4 root on partition 3)
rootfs-radxacm5io.tar.gzRoot filesystem (kernel + DTB under /boot)
build/rk3588_spl_loader*.binMaskrom stage-1 loader for rkdeveloptool db

Flash to eMMC (recommended)

Puts the board in Maskrom mode (hold recovery, power on), then:

rkdeveloptool ld
rkdeveloptool wl 0 lin0-radxacm5io.img
rkdeveloptool rd

This overwrites the existing Debian install.

Flash to SD (whole disk)

# Linux
sudo dd if=lin0-radxacm5io.img of=/dev/sdX bs=4M status=progress conv=fsync
# macOS — use diskutil list; example disk4
diskutil unmountDisk /dev/disk4
sudo dd if=lin0-radxacm5io.img of=/dev/rdisk4 bs=4m

Power the Radxa CM5 IO with 12 V. Console is HDMI (tty0) with a USB keyboard.

Optional knobs:

make radxacm5io RADXA_LINUXVER=master RADXA_P3_MB=128

U-Boot offers two root choices: root=/dev/mmcblk0p3 (eMMC partition 3) and root=LABEL=lin0root. Pick one from the boot menu if the default does not find the rootfs.

Build from source

  1. Add or edit kernel/toybox configs:

    configs/MODEL-linux.config
    configs/MODEL-toybox.config
    
  2. Build:

    make help
    make x86_64
    make pinebookpro
    make radxacm5io
    make # host architecture
  3. Install the resulting rootfs-*.tar.gz (or disk image) on the target.

Static system config lives in etc/ (generic only). TLS trust anchors are fetched at build time from curl.se/ca/cacert.pem into rootfs/etc/ssl/ (SHA-256 pinned as CACERT_SHA256 in the Makefile). wget links against BearSSL + libtls-bearssl and loads /etc/ssl/cert.pem by default.

Usage

  • Username:root
  • Password:lin0

There is no systemd — init is a shell script. Expect to configure the rest yourself.

Networking

Default DNS ships in etc/resolv.conf. On a running system:

vi /etc/resolv.conf

Users

lin0 ships as a single-user system (root only). Toybox useradd / adduser are not built in; add accounts by hand.

On a running system, as root:

# primary group (gid 100 is already in /etc/group as "users")echo'myuser::1000:100:myuser:/home/myuser:/bin/sh'>> /etc/passwd
mkdir -p /home/myuser
chown 1000:100 /home/myuser
passwd myuser

Then su - myuser or log in as myuser at the getty prompt.

Passwords live in /etc/passwd (there is no /etc/shadow). passwd updates that file. Use a free uid (1000+) and an existing gid from /etc/group (default users is 100). Shell must be listed in /etc/shells (default /bin/sh).

To bake a user into the image, edit etc/passwd and etc/group in the tree, create the home directory under rootfs/home/, then rebuild. Lock down root with passwd after first boot.

Extra software

Install what you need on the target (for example wpa_supplicant for Wi-Fi). lin0 is a starting point, not a full desktop stack.

Roadmap

  • Ship HP EliteDesk with firmware built into the kernel
  • Make the system able to compile itself
  • Improve the Raspberry Pi 3B+ rootfs
  • Load modules and start daemons from init
  • Better login/issue screen (something like ly)
  • Man pages
  • Add lin0 to fetch and similar tools

Site pages

The public site is the static files under www/, served from the bare repo at terminal.pink/lin0. Hand-write www/index.html. captain fills in log.html, tree.html, refs.html, and per-commit pages. It never edits index.html.

Only www/ is exported to the forge. Links that point outside that folder (for example ../docs/) 404 on the site; point at tree.html or copy the page into www/.

Index style

Match this page (and the other repos on terminal.pink):

  • 52-character <pre>, magenta links (#ff00ff), color-scheme: light dark
  • nav line: log | tree | refs
  • lowercase running text; do not indent code snippets
  • clone URL with no .git suffix: git clone https://terminal.pink/lin0

New repo on terminal.pink

Same layout as this one. Replace NAME with the project directory name.

  1. Hand-write www/index.html as above.

  2. Init and commit the tree. Skip build artifacts.

    git init -b main
    git add …
    git commit
  3. Install captain and generate pages. Generated files describe the commit they were built from, so they lag the tip by one unless you make a follow-up refresh commit (--no-verify so the hook does not dirty the tree again).

    /path/to/captain install # post-commit hook
    captain -f
    git add www
    git commit --no-verify -m "www: initial captain pages."
    captain -f
    git add www
    git commit --no-verify -m "www: refresh captain pages."
  4. Create the bare on the Pi and install the forge hooks.

    ssh pi 'cd ~/terminal.pink && git init --bare NAME'

    Copy ~/terminal.pink/captain/hooks/post-receive to NAME/hooks/post-receive. On each push to main it walks every new commit, writes www/* into the bare root (prefix stripped), and appends feed.xml. lin0’s copy of this hook also git push --mirror to GitHub; skip that line until a mirror exists.

    Servrian serves the bare directory as static files. Git’s first request is info/refs?service=git-upload-pack, which 404s unless that name exists. post-update should keep dumb HTTP working:

    #!/bin/sh
    git gc
    git update-server-info
    ln -sfn refs "info/refs?service=git-upload-pack"
  5. Push, then list the project on s.html in the terminal.pink repo.

    git remote add origin pi:terminal.pink/NAME
    git push -u origin main

    SSH clone is pi:terminal.pink/NAME. HTTPS is https://terminal.pink/NAME (no .git suffix; shallow clones are not supported over this dumb transport).

Help

Mailing list: lin0 AT terminal DOT pink

License

BSD 2-Clause. © 2023–2026 Brian Mayer

About

Mirror repository of my distro

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - blmayer/lin0: Mirror repository of my distro · GitHub
Skip to content

Repository files navigation

lin0

License: BSD-2-ClauseRolling releaseDocker Pulls

 _._
e/` '\,.eo-__. lin0 (linux zero) is a
'/.' .|_/e--. '\e super minimal source
,;-o-.'|` //e e\ |` based linux meta
./' ,e0\o //-o.__. ,. \' distribution, aimed
./` /' -/e e\o_/___. \|' at power users or
e|`/`,o-o\ /v-/e_. '\. \. minimalism enthusiasts
'/ ._e._, \ // \` \e |'
'|'"/ \.V | `|' `|'|` it was born from
`|e`|' | # / `|. |`|` exercises in how
e|` ` /\- ,\ e|' '\` minimal a linux system
'` _/ / / \ ` `|' can get.
.,wW'^^^//;^-^;^;w_

Features

  • Linux kernel (no initrd)
  • musl libc
  • mksh (MirBSD Korn Shell)
  • tcc (Tiny C Compiler)
  • toybox
  • Shell-script init (init)

Quick start

git clone https://terminal.pink/lin0
cd lin0
make help# list platforms
make # build for the host architecture

Each platform is a Make target. Outputs are rootfs-<platform>.tar.gz (and a full disk image for some boards).

make x86_64
make pinebookpro
make rpizero # also: make rpizero-img
make radxacm5io # rootfs tarball + hybrid disk image

Edit configs/<platform>-*.config, etc/*, or init, then rebuild — Make only rebuilds what changed.

Images

Prebuilt tarballs live under www/. After download, verify the full SHA-256 digest so the file has not been corrupted or tampered with:

# Linux
sha256sum -c SHA256SUMS
# macOS
shasum -a 256 -c SHA256SUMS

www/SHA256SUMS has the full digests. The sha256 column below is the first 16 hex chars for a quick eyeball check. Arch-only builds have no kernel; the rest do. Raspberry Pi Zero is build-only (not published).

+----------------------+------+------------------+------------------+
| platform | size | sha256 | build |
+----------------------+------+------------------+------------------+
| x86_64 | 4.6M | d9b0345efba6d227 | make x86_64 |
| arm64 | 3.9M | a4f99c89fb6b2d97 | make arm64 |
| hp elite desk 800 g1 | 14M | 73752c23c40d1fdd | make hpelitedesk |
| pinebook pro | 14M | 3e49689772dc0235 | make pinebookpro |
| raspberry pi 3b+ | 35M | 6b859999760e0d59 | make rpi3bplus |
| rpi cm5 + io board | 51M | 06bb5b9fdda241a9 | make rpi-cm5io |
| radxa cm5 + io | 27M | 0af2d1501e4e6c82 | make radxacm5io |
| rpi zero / zero w | — | (local) | make rpizero |
+----------------------+------+------------------+------------------+

Tarballs: www/rootfs-*.tar.gz.

Docker

Prebuilt images for trying the userland or compiling with musl/tcc:

docker pull bleemayer/lin0:latest

See bleemayer/lin0 on Docker Hub. Architectures match the tarballs above.

Install from a tarball

tar -xf rootfs-ARCH.tar.gz -C /mnt/your-root
cp path/to/kernel /mnt/your-root/boot/ # if the tarball has no kernel

Replace ARCH with x86_64, arm64, or a platform name. Kernel name is platform-specific (bzImage, Image, zImage, …).

Files under pkg/ are copied to /home/root/ on the target when present.

Radxa CM5 + IO (mainline)

make radxacm5io builds a hybrid bootable disk image: SPL/U-Boot and the GPT layout come from the official Radxa Debian image; partition 3 is resized and filled with lin0 (mainline kernel + rk3588s-radxa-cm5-io.dtb).

On macOS, Make runs the arm64 compile and the privileged partition formatting inside Docker automatically.

git clone https://terminal.pink/lin0
cd lin0
make radxacm5io
OutputPurpose
lin0-radxacm5io.imgFull GPT image (loader at sector 64, ext4 root on partition 3)
rootfs-radxacm5io.tar.gzRoot filesystem (kernel + DTB under /boot)
build/rk3588_spl_loader*.binMaskrom stage-1 loader for rkdeveloptool db

Flash to eMMC (recommended)

Puts the board in Maskrom mode (hold recovery, power on), then:

rkdeveloptool ld
rkdeveloptool wl 0 lin0-radxacm5io.img
rkdeveloptool rd

This overwrites the existing Debian install.

Flash to SD (whole disk)

# Linux
sudo dd if=lin0-radxacm5io.img of=/dev/sdX bs=4M status=progress conv=fsync
# macOS — use diskutil list; example disk4
diskutil unmountDisk /dev/disk4
sudo dd if=lin0-radxacm5io.img of=/dev/rdisk4 bs=4m

Power the Radxa CM5 IO with 12 V. Console is HDMI (tty0) with a USB keyboard.

Optional knobs:

make radxacm5io RADXA_LINUXVER=master RADXA_P3_MB=128

U-Boot offers two root choices: root=/dev/mmcblk0p3 (eMMC partition 3) and root=LABEL=lin0root. Pick one from the boot menu if the default does not find the rootfs.

Build from source

  1. Add or edit kernel/toybox configs:

    configs/MODEL-linux.config
    configs/MODEL-toybox.config
    
  2. Build:

    make help
    make x86_64
    make pinebookpro
    make radxacm5io
    make # host architecture
  3. Install the resulting rootfs-*.tar.gz (or disk image) on the target.

Static system config lives in etc/ (generic only). TLS trust anchors are fetched at build time from curl.se/ca/cacert.pem into rootfs/etc/ssl/ (SHA-256 pinned as CACERT_SHA256 in the Makefile). wget links against BearSSL + libtls-bearssl and loads /etc/ssl/cert.pem by default.

Usage

  • Username:root
  • Password:lin0

There is no systemd — init is a shell script. Expect to configure the rest yourself.

Networking

Default DNS ships in etc/resolv.conf. On a running system:

vi /etc/resolv.conf

Users

lin0 ships as a single-user system (root only). Toybox useradd / adduser are not built in; add accounts by hand.

On a running system, as root:

# primary group (gid 100 is already in /etc/group as "users")echo'myuser::1000:100:myuser:/home/myuser:/bin/sh'>> /etc/passwd
mkdir -p /home/myuser
chown 1000:100 /home/myuser
passwd myuser

Then su - myuser or log in as myuser at the getty prompt.

Passwords live in /etc/passwd (there is no /etc/shadow). passwd updates that file. Use a free uid (1000+) and an existing gid from /etc/group (default users is 100). Shell must be listed in /etc/shells (default /bin/sh).

To bake a user into the image, edit etc/passwd and etc/group in the tree, create the home directory under rootfs/home/, then rebuild. Lock down root with passwd after first boot.

Extra software

Install what you need on the target (for example wpa_supplicant for Wi-Fi). lin0 is a starting point, not a full desktop stack.

Roadmap

  • Ship HP EliteDesk with firmware built into the kernel
  • Make the system able to compile itself
  • Improve the Raspberry Pi 3B+ rootfs
  • Load modules and start daemons from init
  • Better login/issue screen (something like ly)
  • Man pages
  • Add lin0 to fetch and similar tools

Site pages

The public site is the static files under www/, served from the bare repo at terminal.pink/lin0. Hand-write www/index.html. captain fills in log.html, tree.html, refs.html, and per-commit pages. It never edits index.html.

Only www/ is exported to the forge. Links that point outside that folder (for example ../docs/) 404 on the site; point at tree.html or copy the page into www/.

Index style

Match this page (and the other repos on terminal.pink):

  • 52-character <pre>, magenta links (#ff00ff), color-scheme: light dark
  • nav line: log | tree | refs
  • lowercase running text; do not indent code snippets
  • clone URL with no .git suffix: git clone https://terminal.pink/lin0

New repo on terminal.pink

Same layout as this one. Replace NAME with the project directory name.

  1. Hand-write www/index.html as above.

  2. Init and commit the tree. Skip build artifacts.

    git init -b main
    git add …
    git commit
  3. Install captain and generate pages. Generated files describe the commit they were built from, so they lag the tip by one unless you make a follow-up refresh commit (--no-verify so the hook does not dirty the tree again).

    /path/to/captain install # post-commit hook
    captain -f
    git add www
    git commit --no-verify -m "www: initial captain pages."
    captain -f
    git add www
    git commit --no-verify -m "www: refresh captain pages."
  4. Create the bare on the Pi and install the forge hooks.

    ssh pi 'cd ~/terminal.pink && git init --bare NAME'

    Copy ~/terminal.pink/captain/hooks/post-receive to NAME/hooks/post-receive. On each push to main it walks every new commit, writes www/* into the bare root (prefix stripped), and appends feed.xml. lin0’s copy of this hook also git push --mirror to GitHub; skip that line until a mirror exists.

    Servrian serves the bare directory as static files. Git’s first request is info/refs?service=git-upload-pack, which 404s unless that name exists. post-update should keep dumb HTTP working:

    #!/bin/sh
    git gc
    git update-server-info
    ln -sfn refs "info/refs?service=git-upload-pack"
  5. Push, then list the project on s.html in the terminal.pink repo.

    git remote add origin pi:terminal.pink/NAME
    git push -u origin main

    SSH clone is pi:terminal.pink/NAME. HTTPS is https://terminal.pink/NAME (no .git suffix; shallow clones are not supported over this dumb transport).

Help

Mailing list: lin0 AT terminal DOT pink

License

BSD 2-Clause. © 2023–2026 Brian Mayer

About

Mirror repository of my distro

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - blmayer/lin0: Mirror repository of my distro · GitHub
Skip to content

Repository files navigation

lin0

License: BSD-2-ClauseRolling releaseDocker Pulls

 _._
e/` '\,.eo-__. lin0 (linux zero) is a
'/.' .|_/e--. '\e super minimal source
,;-o-.'|` //e e\ |` based linux meta
./' ,e0\o //-o.__. ,. \' distribution, aimed
./` /' -/e e\o_/___. \|' at power users or
e|`/`,o-o\ /v-/e_. '\. \. minimalism enthusiasts
'/ ._e._, \ // \` \e |'
'|'"/ \.V | `|' `|'|` it was born from
`|e`|' | # / `|. |`|` exercises in how
e|` ` /\- ,\ e|' '\` minimal a linux system
'` _/ / / \ ` `|' can get.
.,wW'^^^//;^-^;^;w_

Features

  • Linux kernel (no initrd)
  • musl libc
  • mksh (MirBSD Korn Shell)
  • tcc (Tiny C Compiler)
  • toybox
  • Shell-script init (init)

Quick start

git clone https://terminal.pink/lin0
cd lin0
make help# list platforms
make # build for the host architecture

Each platform is a Make target. Outputs are rootfs-<platform>.tar.gz (and a full disk image for some boards).

make x86_64
make pinebookpro
make rpizero # also: make rpizero-img
make radxacm5io # rootfs tarball + hybrid disk image

Edit configs/<platform>-*.config, etc/*, or init, then rebuild — Make only rebuilds what changed.

Images

Prebuilt tarballs live under www/. After download, verify the full SHA-256 digest so the file has not been corrupted or tampered with:

# Linux
sha256sum -c SHA256SUMS
# macOS
shasum -a 256 -c SHA256SUMS

www/SHA256SUMS has the full digests. The sha256 column below is the first 16 hex chars for a quick eyeball check. Arch-only builds have no kernel; the rest do. Raspberry Pi Zero is build-only (not published).

+----------------------+------+------------------+------------------+
| platform | size | sha256 | build |
+----------------------+------+------------------+------------------+
| x86_64 | 4.6M | d9b0345efba6d227 | make x86_64 |
| arm64 | 3.9M | a4f99c89fb6b2d97 | make arm64 |
| hp elite desk 800 g1 | 14M | 73752c23c40d1fdd | make hpelitedesk |
| pinebook pro | 14M | 3e49689772dc0235 | make pinebookpro |
| raspberry pi 3b+ | 35M | 6b859999760e0d59 | make rpi3bplus |
| rpi cm5 + io board | 51M | 06bb5b9fdda241a9 | make rpi-cm5io |
| radxa cm5 + io | 27M | 0af2d1501e4e6c82 | make radxacm5io |
| rpi zero / zero w | — | (local) | make rpizero |
+----------------------+------+------------------+------------------+

Tarballs: www/rootfs-*.tar.gz.

Docker

Prebuilt images for trying the userland or compiling with musl/tcc:

docker pull bleemayer/lin0:latest

See bleemayer/lin0 on Docker Hub. Architectures match the tarballs above.

Install from a tarball

tar -xf rootfs-ARCH.tar.gz -C /mnt/your-root
cp path/to/kernel /mnt/your-root/boot/ # if the tarball has no kernel

Replace ARCH with x86_64, arm64, or a platform name. Kernel name is platform-specific (bzImage, Image, zImage, …).

Files under pkg/ are copied to /home/root/ on the target when present.

Radxa CM5 + IO (mainline)

make radxacm5io builds a hybrid bootable disk image: SPL/U-Boot and the GPT layout come from the official Radxa Debian image; partition 3 is resized and filled with lin0 (mainline kernel + rk3588s-radxa-cm5-io.dtb).

On macOS, Make runs the arm64 compile and the privileged partition formatting inside Docker automatically.

git clone https://terminal.pink/lin0
cd lin0
make radxacm5io
OutputPurpose
lin0-radxacm5io.imgFull GPT image (loader at sector 64, ext4 root on partition 3)
rootfs-radxacm5io.tar.gzRoot filesystem (kernel + DTB under /boot)
build/rk3588_spl_loader*.binMaskrom stage-1 loader for rkdeveloptool db

Flash to eMMC (recommended)

Puts the board in Maskrom mode (hold recovery, power on), then:

rkdeveloptool ld
rkdeveloptool wl 0 lin0-radxacm5io.img
rkdeveloptool rd

This overwrites the existing Debian install.

Flash to SD (whole disk)

# Linux
sudo dd if=lin0-radxacm5io.img of=/dev/sdX bs=4M status=progress conv=fsync
# macOS — use diskutil list; example disk4
diskutil unmountDisk /dev/disk4
sudo dd if=lin0-radxacm5io.img of=/dev/rdisk4 bs=4m

Power the Radxa CM5 IO with 12 V. Console is HDMI (tty0) with a USB keyboard.

Optional knobs:

make radxacm5io RADXA_LINUXVER=master RADXA_P3_MB=128

U-Boot offers two root choices: root=/dev/mmcblk0p3 (eMMC partition 3) and root=LABEL=lin0root. Pick one from the boot menu if the default does not find the rootfs.

Build from source

  1. Add or edit kernel/toybox configs:

    configs/MODEL-linux.config
    configs/MODEL-toybox.config
    
  2. Build:

    make help
    make x86_64
    make pinebookpro
    make radxacm5io
    make # host architecture
  3. Install the resulting rootfs-*.tar.gz (or disk image) on the target.

Static system config lives in etc/ (generic only). TLS trust anchors are fetched at build time from curl.se/ca/cacert.pem into rootfs/etc/ssl/ (SHA-256 pinned as CACERT_SHA256 in the Makefile). wget links against BearSSL + libtls-bearssl and loads /etc/ssl/cert.pem by default.

Usage

  • Username:root
  • Password:lin0

There is no systemd — init is a shell script. Expect to configure the rest yourself.

Networking

Default DNS ships in etc/resolv.conf. On a running system:

vi /etc/resolv.conf

Users

lin0 ships as a single-user system (root only). Toybox useradd / adduser are not built in; add accounts by hand.

On a running system, as root:

# primary group (gid 100 is already in /etc/group as "users")echo'myuser::1000:100:myuser:/home/myuser:/bin/sh'>> /etc/passwd
mkdir -p /home/myuser
chown 1000:100 /home/myuser
passwd myuser

Then su - myuser or log in as myuser at the getty prompt.

Passwords live in /etc/passwd (there is no /etc/shadow). passwd updates that file. Use a free uid (1000+) and an existing gid from /etc/group (default users is 100). Shell must be listed in /etc/shells (default /bin/sh).

To bake a user into the image, edit etc/passwd and etc/group in the tree, create the home directory under rootfs/home/, then rebuild. Lock down root with passwd after first boot.

Extra software

Install what you need on the target (for example wpa_supplicant for Wi-Fi). lin0 is a starting point, not a full desktop stack.

Roadmap

  • Ship HP EliteDesk with firmware built into the kernel
  • Make the system able to compile itself
  • Improve the Raspberry Pi 3B+ rootfs
  • Load modules and start daemons from init
  • Better login/issue screen (something like ly)
  • Man pages
  • Add lin0 to fetch and similar tools

Site pages

The public site is the static files under www/, served from the bare repo at terminal.pink/lin0. Hand-write www/index.html. captain fills in log.html, tree.html, refs.html, and per-commit pages. It never edits index.html.

Only www/ is exported to the forge. Links that point outside that folder (for example ../docs/) 404 on the site; point at tree.html or copy the page into www/.

Index style

Match this page (and the other repos on terminal.pink):

  • 52-character <pre>, magenta links (#ff00ff), color-scheme: light dark
  • nav line: log | tree | refs
  • lowercase running text; do not indent code snippets
  • clone URL with no .git suffix: git clone https://terminal.pink/lin0

New repo on terminal.pink

Same layout as this one. Replace NAME with the project directory name.

  1. Hand-write www/index.html as above.

  2. Init and commit the tree. Skip build artifacts.

    git init -b main
    git add …
    git commit
  3. Install captain and generate pages. Generated files describe the commit they were built from, so they lag the tip by one unless you make a follow-up refresh commit (--no-verify so the hook does not dirty the tree again).

    /path/to/captain install # post-commit hook
    captain -f
    git add www
    git commit --no-verify -m "www: initial captain pages."
    captain -f
    git add www
    git commit --no-verify -m "www: refresh captain pages."
  4. Create the bare on the Pi and install the forge hooks.

    ssh pi 'cd ~/terminal.pink && git init --bare NAME'

    Copy ~/terminal.pink/captain/hooks/post-receive to NAME/hooks/post-receive. On each push to main it walks every new commit, writes www/* into the bare root (prefix stripped), and appends feed.xml. lin0’s copy of this hook also git push --mirror to GitHub; skip that line until a mirror exists.

    Servrian serves the bare directory as static files. Git’s first request is info/refs?service=git-upload-pack, which 404s unless that name exists. post-update should keep dumb HTTP working:

    #!/bin/sh
    git gc
    git update-server-info
    ln -sfn refs "info/refs?service=git-upload-pack"
  5. Push, then list the project on s.html in the terminal.pink repo.

    git remote add origin pi:terminal.pink/NAME
    git push -u origin main

    SSH clone is pi:terminal.pink/NAME. HTTPS is https://terminal.pink/NAME (no .git suffix; shallow clones are not supported over this dumb transport).

Help

Mailing list: lin0 AT terminal DOT pink

License

BSD 2-Clause. © 2023–2026 Brian Mayer

About

Mirror repository of my distro

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' GitHub - blmayer/lin0: Mirror repository of my distro · GitHub
Skip to content

Repository files navigation

lin0

License: BSD-2-ClauseRolling releaseDocker Pulls

 _._
e/` '\,.eo-__. lin0 (linux zero) is a
'/.' .|_/e--. '\e super minimal source
,;-o-.'|` //e e\ |` based linux meta
./' ,e0\o //-o.__. ,. \' distribution, aimed
./` /' -/e e\o_/___. \|' at power users or
e|`/`,o-o\ /v-/e_. '\. \. minimalism enthusiasts
'/ ._e._, \ // \` \e |'
'|'"/ \.V | `|' `|'|` it was born from
`|e`|' | # / `|. |`|` exercises in how
e|` ` /\- ,\ e|' '\` minimal a linux system
'` _/ / / \ ` `|' can get.
.,wW'^^^//;^-^;^;w_

Features

  • Linux kernel (no initrd)
  • musl libc
  • mksh (MirBSD Korn Shell)
  • tcc (Tiny C Compiler)
  • toybox
  • Shell-script init (init)

Quick start

git clone https://terminal.pink/lin0
cd lin0
make help# list platforms
make # build for the host architecture

Each platform is a Make target. Outputs are rootfs-<platform>.tar.gz (and a full disk image for some boards).

make x86_64
make pinebookpro
make rpizero # also: make rpizero-img
make radxacm5io # rootfs tarball + hybrid disk image

Edit configs/<platform>-*.config, etc/*, or init, then rebuild — Make only rebuilds what changed.

Images

Prebuilt tarballs live under www/. After download, verify the full SHA-256 digest so the file has not been corrupted or tampered with:

# Linux
sha256sum -c SHA256SUMS
# macOS
shasum -a 256 -c SHA256SUMS

www/SHA256SUMS has the full digests. The sha256 column below is the first 16 hex chars for a quick eyeball check. Arch-only builds have no kernel; the rest do. Raspberry Pi Zero is build-only (not published).

+----------------------+------+------------------+------------------+
| platform | size | sha256 | build |
+----------------------+------+------------------+------------------+
| x86_64 | 4.6M | d9b0345efba6d227 | make x86_64 |
| arm64 | 3.9M | a4f99c89fb6b2d97 | make arm64 |
| hp elite desk 800 g1 | 14M | 73752c23c40d1fdd | make hpelitedesk |
| pinebook pro | 14M | 3e49689772dc0235 | make pinebookpro |
| raspberry pi 3b+ | 35M | 6b859999760e0d59 | make rpi3bplus |
| rpi cm5 + io board | 51M | 06bb5b9fdda241a9 | make rpi-cm5io |
| radxa cm5 + io | 27M | 0af2d1501e4e6c82 | make radxacm5io |
| rpi zero / zero w | — | (local) | make rpizero |
+----------------------+------+------------------+------------------+

Tarballs: www/rootfs-*.tar.gz.

Docker

Prebuilt images for trying the userland or compiling with musl/tcc:

docker pull bleemayer/lin0:latest

See bleemayer/lin0 on Docker Hub. Architectures match the tarballs above.

Install from a tarball

tar -xf rootfs-ARCH.tar.gz -C /mnt/your-root
cp path/to/kernel /mnt/your-root/boot/ # if the tarball has no kernel

Replace ARCH with x86_64, arm64, or a platform name. Kernel name is platform-specific (bzImage, Image, zImage, …).

Files under pkg/ are copied to /home/root/ on the target when present.

Radxa CM5 + IO (mainline)

make radxacm5io builds a hybrid bootable disk image: SPL/U-Boot and the GPT layout come from the official Radxa Debian image; partition 3 is resized and filled with lin0 (mainline kernel + rk3588s-radxa-cm5-io.dtb).

On macOS, Make runs the arm64 compile and the privileged partition formatting inside Docker automatically.

git clone https://terminal.pink/lin0
cd lin0
make radxacm5io
OutputPurpose
lin0-radxacm5io.imgFull GPT image (loader at sector 64, ext4 root on partition 3)
rootfs-radxacm5io.tar.gzRoot filesystem (kernel + DTB under /boot)
build/rk3588_spl_loader*.binMaskrom stage-1 loader for rkdeveloptool db

Flash to eMMC (recommended)

Puts the board in Maskrom mode (hold recovery, power on), then:

rkdeveloptool ld
rkdeveloptool wl 0 lin0-radxacm5io.img
rkdeveloptool rd

This overwrites the existing Debian install.

Flash to SD (whole disk)

# Linux
sudo dd if=lin0-radxacm5io.img of=/dev/sdX bs=4M status=progress conv=fsync
# macOS — use diskutil list; example disk4
diskutil unmountDisk /dev/disk4
sudo dd if=lin0-radxacm5io.img of=/dev/rdisk4 bs=4m

Power the Radxa CM5 IO with 12 V. Console is HDMI (tty0) with a USB keyboard.

Optional knobs:

make radxacm5io RADXA_LINUXVER=master RADXA_P3_MB=128

U-Boot offers two root choices: root=/dev/mmcblk0p3 (eMMC partition 3) and root=LABEL=lin0root. Pick one from the boot menu if the default does not find the rootfs.

Build from source

  1. Add or edit kernel/toybox configs:

    configs/MODEL-linux.config
    configs/MODEL-toybox.config
    
  2. Build:

    make help
    make x86_64
    make pinebookpro
    make radxacm5io
    make # host architecture
  3. Install the resulting rootfs-*.tar.gz (or disk image) on the target.

Static system config lives in etc/ (generic only). TLS trust anchors are fetched at build time from curl.se/ca/cacert.pem into rootfs/etc/ssl/ (SHA-256 pinned as CACERT_SHA256 in the Makefile). wget links against BearSSL + libtls-bearssl and loads /etc/ssl/cert.pem by default.

Usage

  • Username:root
  • Password:lin0

There is no systemd — init is a shell script. Expect to configure the rest yourself.

Networking

Default DNS ships in etc/resolv.conf. On a running system:

vi /etc/resolv.conf

Users

lin0 ships as a single-user system (root only). Toybox useradd / adduser are not built in; add accounts by hand.

On a running system, as root:

# primary group (gid 100 is already in /etc/group as "users")echo'myuser::1000:100:myuser:/home/myuser:/bin/sh'>> /etc/passwd
mkdir -p /home/myuser
chown 1000:100 /home/myuser
passwd myuser

Then su - myuser or log in as myuser at the getty prompt.

Passwords live in /etc/passwd (there is no /etc/shadow). passwd updates that file. Use a free uid (1000+) and an existing gid from /etc/group (default users is 100). Shell must be listed in /etc/shells (default /bin/sh).

To bake a user into the image, edit etc/passwd and etc/group in the tree, create the home directory under rootfs/home/, then rebuild. Lock down root with passwd after first boot.

Extra software

Install what you need on the target (for example wpa_supplicant for Wi-Fi). lin0 is a starting point, not a full desktop stack.

Roadmap

  • Ship HP EliteDesk with firmware built into the kernel
  • Make the system able to compile itself
  • Improve the Raspberry Pi 3B+ rootfs
  • Load modules and start daemons from init
  • Better login/issue screen (something like ly)
  • Man pages
  • Add lin0 to fetch and similar tools

Site pages

The public site is the static files under www/, served from the bare repo at terminal.pink/lin0. Hand-write www/index.html. captain fills in log.html, tree.html, refs.html, and per-commit pages. It never edits index.html.

Only www/ is exported to the forge. Links that point outside that folder (for example ../docs/) 404 on the site; point at tree.html or copy the page into www/.

Index style

Match this page (and the other repos on terminal.pink):

  • 52-character <pre>, magenta links (#ff00ff), color-scheme: light dark
  • nav line: log | tree | refs
  • lowercase running text; do not indent code snippets
  • clone URL with no .git suffix: git clone https://terminal.pink/lin0

New repo on terminal.pink

Same layout as this one. Replace NAME with the project directory name.

  1. Hand-write www/index.html as above.

  2. Init and commit the tree. Skip build artifacts.

    git init -b main
    git add …
    git commit
  3. Install captain and generate pages. Generated files describe the commit they were built from, so they lag the tip by one unless you make a follow-up refresh commit (--no-verify so the hook does not dirty the tree again).

    /path/to/captain install # post-commit hook
    captain -f
    git add www
    git commit --no-verify -m "www: initial captain pages."
    captain -f
    git add www
    git commit --no-verify -m "www: refresh captain pages."
  4. Create the bare on the Pi and install the forge hooks.

    ssh pi 'cd ~/terminal.pink && git init --bare NAME'

    Copy ~/terminal.pink/captain/hooks/post-receive to NAME/hooks/post-receive. On each push to main it walks every new commit, writes www/* into the bare root (prefix stripped), and appends feed.xml. lin0’s copy of this hook also git push --mirror to GitHub; skip that line until a mirror exists.

    Servrian serves the bare directory as static files. Git’s first request is info/refs?service=git-upload-pack, which 404s unless that name exists. post-update should keep dumb HTTP working:

    #!/bin/sh
    git gc
    git update-server-info
    ln -sfn refs "info/refs?service=git-upload-pack"
  5. Push, then list the project on s.html in the terminal.pink repo.

    git remote add origin pi:terminal.pink/NAME
    git push -u origin main

    SSH clone is pi:terminal.pink/NAME. HTTPS is https://terminal.pink/NAME (no .git suffix; shallow clones are not supported over this dumb transport).

Help

Mailing list: lin0 AT terminal DOT pink

License

BSD 2-Clause. © 2023–2026 Brian Mayer

About

Mirror repository of my distro

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - blmayer/lin0: Mirror repository of my distro · GitHub
Skip to content

Repository files navigation

lin0

License: BSD-2-ClauseRolling releaseDocker Pulls

 _._
e/` '\,.eo-__. lin0 (linux zero) is a
'/.' .|_/e--. '\e super minimal source
,;-o-.'|` //e e\ |` based linux meta
./' ,e0\o //-o.__. ,. \' distribution, aimed
./` /' -/e e\o_/___. \|' at power users or
e|`/`,o-o\ /v-/e_. '\. \. minimalism enthusiasts
'/ ._e._, \ // \` \e |'
'|'"/ \.V | `|' `|'|` it was born from
`|e`|' | # / `|. |`|` exercises in how
e|` ` /\- ,\ e|' '\` minimal a linux system
'` _/ / / \ ` `|' can get.
.,wW'^^^//;^-^;^;w_

Features

  • Linux kernel (no initrd)
  • musl libc
  • mksh (MirBSD Korn Shell)
  • tcc (Tiny C Compiler)
  • toybox
  • Shell-script init (init)

Quick start

git clone https://terminal.pink/lin0
cd lin0
make help# list platforms
make # build for the host architecture

Each platform is a Make target. Outputs are rootfs-<platform>.tar.gz (and a full disk image for some boards).

make x86_64
make pinebookpro
make rpizero # also: make rpizero-img
make radxacm5io # rootfs tarball + hybrid disk image

Edit configs/<platform>-*.config, etc/*, or init, then rebuild — Make only rebuilds what changed.

Images

Prebuilt tarballs live under www/. After download, verify the full SHA-256 digest so the file has not been corrupted or tampered with:

# Linux
sha256sum -c SHA256SUMS
# macOS
shasum -a 256 -c SHA256SUMS

www/SHA256SUMS has the full digests. The sha256 column below is the first 16 hex chars for a quick eyeball check. Arch-only builds have no kernel; the rest do. Raspberry Pi Zero is build-only (not published).

+----------------------+------+------------------+------------------+
| platform | size | sha256 | build |
+----------------------+------+------------------+------------------+
| x86_64 | 4.6M | d9b0345efba6d227 | make x86_64 |
| arm64 | 3.9M | a4f99c89fb6b2d97 | make arm64 |
| hp elite desk 800 g1 | 14M | 73752c23c40d1fdd | make hpelitedesk |
| pinebook pro | 14M | 3e49689772dc0235 | make pinebookpro |
| raspberry pi 3b+ | 35M | 6b859999760e0d59 | make rpi3bplus |
| rpi cm5 + io board | 51M | 06bb5b9fdda241a9 | make rpi-cm5io |
| radxa cm5 + io | 27M | 0af2d1501e4e6c82 | make radxacm5io |
| rpi zero / zero w | — | (local) | make rpizero |
+----------------------+------+------------------+------------------+

Tarballs: www/rootfs-*.tar.gz.

Docker

Prebuilt images for trying the userland or compiling with musl/tcc:

docker pull bleemayer/lin0:latest

See bleemayer/lin0 on Docker Hub. Architectures match the tarballs above.

Install from a tarball

tar -xf rootfs-ARCH.tar.gz -C /mnt/your-root
cp path/to/kernel /mnt/your-root/boot/ # if the tarball has no kernel

Replace ARCH with x86_64, arm64, or a platform name. Kernel name is platform-specific (bzImage, Image, zImage, …).

Files under pkg/ are copied to /home/root/ on the target when present.

Radxa CM5 + IO (mainline)

make radxacm5io builds a hybrid bootable disk image: SPL/U-Boot and the GPT layout come from the official Radxa Debian image; partition 3 is resized and filled with lin0 (mainline kernel + rk3588s-radxa-cm5-io.dtb).

On macOS, Make runs the arm64 compile and the privileged partition formatting inside Docker automatically.

git clone https://terminal.pink/lin0
cd lin0
make radxacm5io
OutputPurpose
lin0-radxacm5io.imgFull GPT image (loader at sector 64, ext4 root on partition 3)
rootfs-radxacm5io.tar.gzRoot filesystem (kernel + DTB under /boot)
build/rk3588_spl_loader*.binMaskrom stage-1 loader for rkdeveloptool db

Flash to eMMC (recommended)

Puts the board in Maskrom mode (hold recovery, power on), then:

rkdeveloptool ld
rkdeveloptool wl 0 lin0-radxacm5io.img
rkdeveloptool rd

This overwrites the existing Debian install.

Flash to SD (whole disk)

# Linux
sudo dd if=lin0-radxacm5io.img of=/dev/sdX bs=4M status=progress conv=fsync
# macOS — use diskutil list; example disk4
diskutil unmountDisk /dev/disk4
sudo dd if=lin0-radxacm5io.img of=/dev/rdisk4 bs=4m

Power the Radxa CM5 IO with 12 V. Console is HDMI (tty0) with a USB keyboard.

Optional knobs:

make radxacm5io RADXA_LINUXVER=master RADXA_P3_MB=128

U-Boot offers two root choices: root=/dev/mmcblk0p3 (eMMC partition 3) and root=LABEL=lin0root. Pick one from the boot menu if the default does not find the rootfs.

Build from source

  1. Add or edit kernel/toybox configs:

    configs/MODEL-linux.config
    configs/MODEL-toybox.config
    
  2. Build:

    make help
    make x86_64
    make pinebookpro
    make radxacm5io
    make # host architecture
  3. Install the resulting rootfs-*.tar.gz (or disk image) on the target.

Static system config lives in etc/ (generic only). TLS trust anchors are fetched at build time from curl.se/ca/cacert.pem into rootfs/etc/ssl/ (SHA-256 pinned as CACERT_SHA256 in the Makefile). wget links against BearSSL + libtls-bearssl and loads /etc/ssl/cert.pem by default.

Usage

  • Username:root
  • Password:lin0

There is no systemd — init is a shell script. Expect to configure the rest yourself.

Networking

Default DNS ships in etc/resolv.conf. On a running system:

vi /etc/resolv.conf

Users

lin0 ships as a single-user system (root only). Toybox useradd / adduser are not built in; add accounts by hand.

On a running system, as root:

# primary group (gid 100 is already in /etc/group as "users")echo'myuser::1000:100:myuser:/home/myuser:/bin/sh'>> /etc/passwd
mkdir -p /home/myuser
chown 1000:100 /home/myuser
passwd myuser

Then su - myuser or log in as myuser at the getty prompt.

Passwords live in /etc/passwd (there is no /etc/shadow). passwd updates that file. Use a free uid (1000+) and an existing gid from /etc/group (default users is 100). Shell must be listed in /etc/shells (default /bin/sh).

To bake a user into the image, edit etc/passwd and etc/group in the tree, create the home directory under rootfs/home/, then rebuild. Lock down root with passwd after first boot.

Extra software

Install what you need on the target (for example wpa_supplicant for Wi-Fi). lin0 is a starting point, not a full desktop stack.

Roadmap

  • Ship HP EliteDesk with firmware built into the kernel
  • Make the system able to compile itself
  • Improve the Raspberry Pi 3B+ rootfs
  • Load modules and start daemons from init
  • Better login/issue screen (something like ly)
  • Man pages
  • Add lin0 to fetch and similar tools

Site pages

The public site is the static files under www/, served from the bare repo at terminal.pink/lin0. Hand-write www/index.html. captain fills in log.html, tree.html, refs.html, and per-commit pages. It never edits index.html.

Only www/ is exported to the forge. Links that point outside that folder (for example ../docs/) 404 on the site; point at tree.html or copy the page into www/.

Index style

Match this page (and the other repos on terminal.pink):

  • 52-character <pre>, magenta links (#ff00ff), color-scheme: light dark
  • nav line: log | tree | refs
  • lowercase running text; do not indent code snippets
  • clone URL with no .git suffix: git clone https://terminal.pink/lin0

New repo on terminal.pink

Same layout as this one. Replace NAME with the project directory name.

  1. Hand-write www/index.html as above.

  2. Init and commit the tree. Skip build artifacts.

    git init -b main
    git add …
    git commit
  3. Install captain and generate pages. Generated files describe the commit they were built from, so they lag the tip by one unless you make a follow-up refresh commit (--no-verify so the hook does not dirty the tree again).

    /path/to/captain install # post-commit hook
    captain -f
    git add www
    git commit --no-verify -m "www: initial captain pages."
    captain -f
    git add www
    git commit --no-verify -m "www: refresh captain pages."
  4. Create the bare on the Pi and install the forge hooks.

    ssh pi 'cd ~/terminal.pink && git init --bare NAME'

    Copy ~/terminal.pink/captain/hooks/post-receive to NAME/hooks/post-receive. On each push to main it walks every new commit, writes www/* into the bare root (prefix stripped), and appends feed.xml. lin0’s copy of this hook also git push --mirror to GitHub; skip that line until a mirror exists.

    Servrian serves the bare directory as static files. Git’s first request is info/refs?service=git-upload-pack, which 404s unless that name exists. post-update should keep dumb HTTP working:

    #!/bin/sh
    git gc
    git update-server-info
    ln -sfn refs "info/refs?service=git-upload-pack"
  5. Push, then list the project on s.html in the terminal.pink repo.

    git remote add origin pi:terminal.pink/NAME
    git push -u origin main

    SSH clone is pi:terminal.pink/NAME. HTTPS is https://terminal.pink/NAME (no .git suffix; shallow clones are not supported over this dumb transport).

Help

Mailing list: lin0 AT terminal DOT pink

License

BSD 2-Clause. © 2023–2026 Brian Mayer

About

Mirror repository of my distro

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' GitHub - blmayer/lin0: Mirror repository of my distro · GitHub
Skip to content

Repository files navigation

lin0

License: BSD-2-ClauseRolling releaseDocker Pulls

 _._
e/` '\,.eo-__. lin0 (linux zero) is a
'/.' .|_/e--. '\e super minimal source
,;-o-.'|` //e e\ |` based linux meta
./' ,e0\o //-o.__. ,. \' distribution, aimed
./` /' -/e e\o_/___. \|' at power users or
e|`/`,o-o\ /v-/e_. '\. \. minimalism enthusiasts
'/ ._e._, \ // \` \e |'
'|'"/ \.V | `|' `|'|` it was born from
`|e`|' | # / `|. |`|` exercises in how
e|` ` /\- ,\ e|' '\` minimal a linux system
'` _/ / / \ ` `|' can get.
.,wW'^^^//;^-^;^;w_

Features

  • Linux kernel (no initrd)
  • musl libc
  • mksh (MirBSD Korn Shell)
  • tcc (Tiny C Compiler)
  • toybox
  • Shell-script init (init)

Quick start

git clone https://terminal.pink/lin0
cd lin0
make help# list platforms
make # build for the host architecture

Each platform is a Make target. Outputs are rootfs-<platform>.tar.gz (and a full disk image for some boards).

make x86_64
make pinebookpro
make rpizero # also: make rpizero-img
make radxacm5io # rootfs tarball + hybrid disk image

Edit configs/<platform>-*.config, etc/*, or init, then rebuild — Make only rebuilds what changed.

Images

Prebuilt tarballs live under www/. After download, verify the full SHA-256 digest so the file has not been corrupted or tampered with:

# Linux
sha256sum -c SHA256SUMS
# macOS
shasum -a 256 -c SHA256SUMS

www/SHA256SUMS has the full digests. The sha256 column below is the first 16 hex chars for a quick eyeball check. Arch-only builds have no kernel; the rest do. Raspberry Pi Zero is build-only (not published).

+----------------------+------+------------------+------------------+
| platform | size | sha256 | build |
+----------------------+------+------------------+------------------+
| x86_64 | 4.6M | d9b0345efba6d227 | make x86_64 |
| arm64 | 3.9M | a4f99c89fb6b2d97 | make arm64 |
| hp elite desk 800 g1 | 14M | 73752c23c40d1fdd | make hpelitedesk |
| pinebook pro | 14M | 3e49689772dc0235 | make pinebookpro |
| raspberry pi 3b+ | 35M | 6b859999760e0d59 | make rpi3bplus |
| rpi cm5 + io board | 51M | 06bb5b9fdda241a9 | make rpi-cm5io |
| radxa cm5 + io | 27M | 0af2d1501e4e6c82 | make radxacm5io |
| rpi zero / zero w | — | (local) | make rpizero |
+----------------------+------+------------------+------------------+

Tarballs: www/rootfs-*.tar.gz.

Docker

Prebuilt images for trying the userland or compiling with musl/tcc:

docker pull bleemayer/lin0:latest

See bleemayer/lin0 on Docker Hub. Architectures match the tarballs above.

Install from a tarball

tar -xf rootfs-ARCH.tar.gz -C /mnt/your-root
cp path/to/kernel /mnt/your-root/boot/ # if the tarball has no kernel

Replace ARCH with x86_64, arm64, or a platform name. Kernel name is platform-specific (bzImage, Image, zImage, …).

Files under pkg/ are copied to /home/root/ on the target when present.

Radxa CM5 + IO (mainline)

make radxacm5io builds a hybrid bootable disk image: SPL/U-Boot and the GPT layout come from the official Radxa Debian image; partition 3 is resized and filled with lin0 (mainline kernel + rk3588s-radxa-cm5-io.dtb).

On macOS, Make runs the arm64 compile and the privileged partition formatting inside Docker automatically.

git clone https://terminal.pink/lin0
cd lin0
make radxacm5io
OutputPurpose
lin0-radxacm5io.imgFull GPT image (loader at sector 64, ext4 root on partition 3)
rootfs-radxacm5io.tar.gzRoot filesystem (kernel + DTB under /boot)
build/rk3588_spl_loader*.binMaskrom stage-1 loader for rkdeveloptool db

Flash to eMMC (recommended)

Puts the board in Maskrom mode (hold recovery, power on), then:

rkdeveloptool ld
rkdeveloptool wl 0 lin0-radxacm5io.img
rkdeveloptool rd

This overwrites the existing Debian install.

Flash to SD (whole disk)

# Linux
sudo dd if=lin0-radxacm5io.img of=/dev/sdX bs=4M status=progress conv=fsync
# macOS — use diskutil list; example disk4
diskutil unmountDisk /dev/disk4
sudo dd if=lin0-radxacm5io.img of=/dev/rdisk4 bs=4m

Power the Radxa CM5 IO with 12 V. Console is HDMI (tty0) with a USB keyboard.

Optional knobs:

make radxacm5io RADXA_LINUXVER=master RADXA_P3_MB=128

U-Boot offers two root choices: root=/dev/mmcblk0p3 (eMMC partition 3) and root=LABEL=lin0root. Pick one from the boot menu if the default does not find the rootfs.

Build from source

  1. Add or edit kernel/toybox configs:

    configs/MODEL-linux.config
    configs/MODEL-toybox.config
    
  2. Build:

    make help
    make x86_64
    make pinebookpro
    make radxacm5io
    make # host architecture
  3. Install the resulting rootfs-*.tar.gz (or disk image) on the target.

Static system config lives in etc/ (generic only). TLS trust anchors are fetched at build time from curl.se/ca/cacert.pem into rootfs/etc/ssl/ (SHA-256 pinned as CACERT_SHA256 in the Makefile). wget links against BearSSL + libtls-bearssl and loads /etc/ssl/cert.pem by default.

Usage

  • Username:root
  • Password:lin0

There is no systemd — init is a shell script. Expect to configure the rest yourself.

Networking

Default DNS ships in etc/resolv.conf. On a running system:

vi /etc/resolv.conf

Users

lin0 ships as a single-user system (root only). Toybox useradd / adduser are not built in; add accounts by hand.

On a running system, as root:

# primary group (gid 100 is already in /etc/group as "users")echo'myuser::1000:100:myuser:/home/myuser:/bin/sh'>> /etc/passwd
mkdir -p /home/myuser
chown 1000:100 /home/myuser
passwd myuser

Then su - myuser or log in as myuser at the getty prompt.

Passwords live in /etc/passwd (there is no /etc/shadow). passwd updates that file. Use a free uid (1000+) and an existing gid from /etc/group (default users is 100). Shell must be listed in /etc/shells (default /bin/sh).

To bake a user into the image, edit etc/passwd and etc/group in the tree, create the home directory under rootfs/home/, then rebuild. Lock down root with passwd after first boot.

Extra software

Install what you need on the target (for example wpa_supplicant for Wi-Fi). lin0 is a starting point, not a full desktop stack.

Roadmap

  • Ship HP EliteDesk with firmware built into the kernel
  • Make the system able to compile itself
  • Improve the Raspberry Pi 3B+ rootfs
  • Load modules and start daemons from init
  • Better login/issue screen (something like ly)
  • Man pages
  • Add lin0 to fetch and similar tools

Site pages

The public site is the static files under www/, served from the bare repo at terminal.pink/lin0. Hand-write www/index.html. captain fills in log.html, tree.html, refs.html, and per-commit pages. It never edits index.html.

Only www/ is exported to the forge. Links that point outside that folder (for example ../docs/) 404 on the site; point at tree.html or copy the page into www/.

Index style

Match this page (and the other repos on terminal.pink):

  • 52-character <pre>, magenta links (#ff00ff), color-scheme: light dark
  • nav line: log | tree | refs
  • lowercase running text; do not indent code snippets
  • clone URL with no .git suffix: git clone https://terminal.pink/lin0

New repo on terminal.pink

Same layout as this one. Replace NAME with the project directory name.

  1. Hand-write www/index.html as above.

  2. Init and commit the tree. Skip build artifacts.

    git init -b main
    git add …
    git commit
  3. Install captain and generate pages. Generated files describe the commit they were built from, so they lag the tip by one unless you make a follow-up refresh commit (--no-verify so the hook does not dirty the tree again).

    /path/to/captain install # post-commit hook
    captain -f
    git add www
    git commit --no-verify -m "www: initial captain pages."
    captain -f
    git add www
    git commit --no-verify -m "www: refresh captain pages."
  4. Create the bare on the Pi and install the forge hooks.

    ssh pi 'cd ~/terminal.pink && git init --bare NAME'

    Copy ~/terminal.pink/captain/hooks/post-receive to NAME/hooks/post-receive. On each push to main it walks every new commit, writes www/* into the bare root (prefix stripped), and appends feed.xml. lin0’s copy of this hook also git push --mirror to GitHub; skip that line until a mirror exists.

    Servrian serves the bare directory as static files. Git’s first request is info/refs?service=git-upload-pack, which 404s unless that name exists. post-update should keep dumb HTTP working:

    #!/bin/sh
    git gc
    git update-server-info
    ln -sfn refs "info/refs?service=git-upload-pack"
  5. Push, then list the project on s.html in the terminal.pink repo.

    git remote add origin pi:terminal.pink/NAME
    git push -u origin main

    SSH clone is pi:terminal.pink/NAME. HTTPS is https://terminal.pink/NAME (no .git suffix; shallow clones are not supported over this dumb transport).

Help

Mailing list: lin0 AT terminal DOT pink

License

BSD 2-Clause. © 2023–2026 Brian Mayer

About

Mirror repository of my distro

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); GitHub - blmayer/lin0: Mirror repository of my distro · GitHub
Skip to content

Repository files navigation

lin0

License: BSD-2-ClauseRolling releaseDocker Pulls

 _._
e/` '\,.eo-__. lin0 (linux zero) is a
'/.' .|_/e--. '\e super minimal source
,;-o-.'|` //e e\ |` based linux meta
./' ,e0\o //-o.__. ,. \' distribution, aimed
./` /' -/e e\o_/___. \|' at power users or
e|`/`,o-o\ /v-/e_. '\. \. minimalism enthusiasts
'/ ._e._, \ // \` \e |'
'|'"/ \.V | `|' `|'|` it was born from
`|e`|' | # / `|. |`|` exercises in how
e|` ` /\- ,\ e|' '\` minimal a linux system
'` _/ / / \ ` `|' can get.
.,wW'^^^//;^-^;^;w_

Features

  • Linux kernel (no initrd)
  • musl libc
  • mksh (MirBSD Korn Shell)
  • tcc (Tiny C Compiler)
  • toybox
  • Shell-script init (init)

Quick start

git clone https://terminal.pink/lin0
cd lin0
make help# list platforms
make # build for the host architecture

Each platform is a Make target. Outputs are rootfs-<platform>.tar.gz (and a full disk image for some boards).

make x86_64
make pinebookpro
make rpizero # also: make rpizero-img
make radxacm5io # rootfs tarball + hybrid disk image

Edit configs/<platform>-*.config, etc/*, or init, then rebuild — Make only rebuilds what changed.

Images

Prebuilt tarballs live under www/. After download, verify the full SHA-256 digest so the file has not been corrupted or tampered with:

# Linux
sha256sum -c SHA256SUMS
# macOS
shasum -a 256 -c SHA256SUMS

www/SHA256SUMS has the full digests. The sha256 column below is the first 16 hex chars for a quick eyeball check. Arch-only builds have no kernel; the rest do. Raspberry Pi Zero is build-only (not published).

+----------------------+------+------------------+------------------+
| platform | size | sha256 | build |
+----------------------+------+------------------+------------------+
| x86_64 | 4.6M | d9b0345efba6d227 | make x86_64 |
| arm64 | 3.9M | a4f99c89fb6b2d97 | make arm64 |
| hp elite desk 800 g1 | 14M | 73752c23c40d1fdd | make hpelitedesk |
| pinebook pro | 14M | 3e49689772dc0235 | make pinebookpro |
| raspberry pi 3b+ | 35M | 6b859999760e0d59 | make rpi3bplus |
| rpi cm5 + io board | 51M | 06bb5b9fdda241a9 | make rpi-cm5io |
| radxa cm5 + io | 27M | 0af2d1501e4e6c82 | make radxacm5io |
| rpi zero / zero w | — | (local) | make rpizero |
+----------------------+------+------------------+------------------+

Tarballs: www/rootfs-*.tar.gz.

Docker

Prebuilt images for trying the userland or compiling with musl/tcc:

docker pull bleemayer/lin0:latest

See bleemayer/lin0 on Docker Hub. Architectures match the tarballs above.

Install from a tarball

tar -xf rootfs-ARCH.tar.gz -C /mnt/your-root
cp path/to/kernel /mnt/your-root/boot/ # if the tarball has no kernel

Replace ARCH with x86_64, arm64, or a platform name. Kernel name is platform-specific (bzImage, Image, zImage, …).

Files under pkg/ are copied to /home/root/ on the target when present.

Radxa CM5 + IO (mainline)

make radxacm5io builds a hybrid bootable disk image: SPL/U-Boot and the GPT layout come from the official Radxa Debian image; partition 3 is resized and filled with lin0 (mainline kernel + rk3588s-radxa-cm5-io.dtb).

On macOS, Make runs the arm64 compile and the privileged partition formatting inside Docker automatically.

git clone https://terminal.pink/lin0
cd lin0
make radxacm5io
OutputPurpose
lin0-radxacm5io.imgFull GPT image (loader at sector 64, ext4 root on partition 3)
rootfs-radxacm5io.tar.gzRoot filesystem (kernel + DTB under /boot)
build/rk3588_spl_loader*.binMaskrom stage-1 loader for rkdeveloptool db

Flash to eMMC (recommended)

Puts the board in Maskrom mode (hold recovery, power on), then:

rkdeveloptool ld
rkdeveloptool wl 0 lin0-radxacm5io.img
rkdeveloptool rd

This overwrites the existing Debian install.

Flash to SD (whole disk)

# Linux
sudo dd if=lin0-radxacm5io.img of=/dev/sdX bs=4M status=progress conv=fsync
# macOS — use diskutil list; example disk4
diskutil unmountDisk /dev/disk4
sudo dd if=lin0-radxacm5io.img of=/dev/rdisk4 bs=4m

Power the Radxa CM5 IO with 12 V. Console is HDMI (tty0) with a USB keyboard.

Optional knobs:

make radxacm5io RADXA_LINUXVER=master RADXA_P3_MB=128

U-Boot offers two root choices: root=/dev/mmcblk0p3 (eMMC partition 3) and root=LABEL=lin0root. Pick one from the boot menu if the default does not find the rootfs.

Build from source

  1. Add or edit kernel/toybox configs:

    configs/MODEL-linux.config
    configs/MODEL-toybox.config
    
  2. Build:

    make help
    make x86_64
    make pinebookpro
    make radxacm5io
    make # host architecture
  3. Install the resulting rootfs-*.tar.gz (or disk image) on the target.

Static system config lives in etc/ (generic only). TLS trust anchors are fetched at build time from curl.se/ca/cacert.pem into rootfs/etc/ssl/ (SHA-256 pinned as CACERT_SHA256 in the Makefile). wget links against BearSSL + libtls-bearssl and loads /etc/ssl/cert.pem by default.

Usage

  • Username:root
  • Password:lin0

There is no systemd — init is a shell script. Expect to configure the rest yourself.

Networking

Default DNS ships in etc/resolv.conf. On a running system:

vi /etc/resolv.conf

Users

lin0 ships as a single-user system (root only). Toybox useradd / adduser are not built in; add accounts by hand.

On a running system, as root:

# primary group (gid 100 is already in /etc/group as "users")echo'myuser::1000:100:myuser:/home/myuser:/bin/sh'>> /etc/passwd
mkdir -p /home/myuser
chown 1000:100 /home/myuser
passwd myuser

Then su - myuser or log in as myuser at the getty prompt.

Passwords live in /etc/passwd (there is no /etc/shadow). passwd updates that file. Use a free uid (1000+) and an existing gid from /etc/group (default users is 100). Shell must be listed in /etc/shells (default /bin/sh).

To bake a user into the image, edit etc/passwd and etc/group in the tree, create the home directory under rootfs/home/, then rebuild. Lock down root with passwd after first boot.

Extra software

Install what you need on the target (for example wpa_supplicant for Wi-Fi). lin0 is a starting point, not a full desktop stack.

Roadmap

  • Ship HP EliteDesk with firmware built into the kernel
  • Make the system able to compile itself
  • Improve the Raspberry Pi 3B+ rootfs
  • Load modules and start daemons from init
  • Better login/issue screen (something like ly)
  • Man pages
  • Add lin0 to fetch and similar tools

Site pages

The public site is the static files under www/, served from the bare repo at terminal.pink/lin0. Hand-write www/index.html. captain fills in log.html, tree.html, refs.html, and per-commit pages. It never edits index.html.

Only www/ is exported to the forge. Links that point outside that folder (for example ../docs/) 404 on the site; point at tree.html or copy the page into www/.

Index style

Match this page (and the other repos on terminal.pink):

  • 52-character <pre>, magenta links (#ff00ff), color-scheme: light dark
  • nav line: log | tree | refs
  • lowercase running text; do not indent code snippets
  • clone URL with no .git suffix: git clone https://terminal.pink/lin0

New repo on terminal.pink

Same layout as this one. Replace NAME with the project directory name.

  1. Hand-write www/index.html as above.

  2. Init and commit the tree. Skip build artifacts.

    git init -b main
    git add …
    git commit
  3. Install captain and generate pages. Generated files describe the commit they were built from, so they lag the tip by one unless you make a follow-up refresh commit (--no-verify so the hook does not dirty the tree again).

    /path/to/captain install # post-commit hook
    captain -f
    git add www
    git commit --no-verify -m "www: initial captain pages."
    captain -f
    git add www
    git commit --no-verify -m "www: refresh captain pages."
  4. Create the bare on the Pi and install the forge hooks.

    ssh pi 'cd ~/terminal.pink && git init --bare NAME'

    Copy ~/terminal.pink/captain/hooks/post-receive to NAME/hooks/post-receive. On each push to main it walks every new commit, writes www/* into the bare root (prefix stripped), and appends feed.xml. lin0’s copy of this hook also git push --mirror to GitHub; skip that line until a mirror exists.

    Servrian serves the bare directory as static files. Git’s first request is info/refs?service=git-upload-pack, which 404s unless that name exists. post-update should keep dumb HTTP working:

    #!/bin/sh
    git gc
    git update-server-info
    ln -sfn refs "info/refs?service=git-upload-pack"
  5. Push, then list the project on s.html in the terminal.pink repo.

    git remote add origin pi:terminal.pink/NAME
    git push -u origin main

    SSH clone is pi:terminal.pink/NAME. HTTPS is https://terminal.pink/NAME (no .git suffix; shallow clones are not supported over this dumb transport).

Help

Mailing list: lin0 AT terminal DOT pink

License

BSD 2-Clause. © 2023–2026 Brian Mayer

About

Mirror repository of my distro

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages