diff options
Diffstat (limited to 'www/content/posts')
| -rw-r--r-- | www/content/posts/_index.md (renamed from www/content/posts/_index.html) | 0 | ||||
| -rw-r--r-- | www/content/posts/c-func-ext.md | 101 | ||||
| -rw-r--r-- | www/content/posts/nspawn.md | 206 | ||||
| -rw-r--r-- | www/content/posts/pattern-in-cpp.md | 25 | ||||
| -rw-r--r-- | www/content/posts/use-paddleocr.md | 4 |
5 files changed, 309 insertions, 27 deletions
diff --git a/www/content/posts/_index.html b/www/content/posts/_index.md index 76fa783..76fa783 100644 --- a/www/content/posts/_index.html +++ b/www/content/posts/_index.md diff --git a/www/content/posts/c-func-ext.md b/www/content/posts/c-func-ext.md new file mode 100644 index 0000000..1f5f822 --- /dev/null +++ b/www/content/posts/c-func-ext.md @@ -0,0 +1,101 @@ +--- +title: "Libc/POSIX Function \"Extensions\"" +date: 2025-03-04T13:40:33+08:00 +lastmod: 2025-03-04T13:40:33+08:00 +categories: coding +tags: + - c + - posix +--- + +(I've given up on this, at least for linux pam.) + +Recently, I’ve been working on porting some libraries to GNU/Hurd. Many (old) +libraries use [`*_MAX` constants on POSIX system +interfaces](https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/nframe.html) +to calculate buffer sizes. However, the GNU/Hurd maintainers urge against the +blind use of them and refuse to define them in system headers. When old APIs are +gone, compatibility problems come. To make my life easier, I'll put some +reusable code snippets here to help *fix `*_MAX` bugs*. + +<!--more--> + +```c +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <stdio.h> +#include <errno.h> + +static inline char *xreadlink(const char *restrict path) { + char *buffer; + size_t allocated = 128; + ssize_t len; + + while (1) { + buffer = (char*) malloc(allocated); + if (!buffer) { return NULL; } + len = readlink(path, buffer, allocated); + if (len < (ssize_t) allocated) { return buffer; } + free(buffer); + if (len >= (ssize_t) allocated) { allocated *= 2; continue; } + return NULL; + } + } + + +static inline char *xgethostname(void) { + long max_host_name; + char *buffer; + + max_host_name = sysconf(_SC_HOST_NAME_MAX); + buffer = malloc(max_host_name + 1); + + if (gethostname(buffer, max_host_name + 1)) { + free(buffer); + return NULL; + } + + buffer[max_host_name] = '\0'; + return buffer; +} + +static inline char *xgetcwd(void) { + char *buffer; + size_t allocated = 128; + + while (1) { + buffer = (char*) malloc(allocated); + if (!buffer) { return NULL; } + getcwd(buffer, allocated); + if (buffer) return buffer; + free(buffer); + if (errno == ERANGE) { allocated *= 2; continue; } + return NULL; + } +} + +static inline __attribute__((__format__(__printf__, 2, 3))) int +xsprintf(char **buf_ptr, const char *restrict format, ...) { + char *buffer; + int ret; + + va_list args; + va_start(args, format); + + ret = snprintf(NULL, 0, format, args); + if (ret < 0) { goto out; } + + buffer = malloc(ret + 1); + if (!buffer) { ret = -1; goto out; } + + ret = snprintf(NULL, 0, format, args); + if (ret < 0) { free(buffer); goto out; } + + *buf_ptr = buffer; + +out: + va_end(args); + return ret; +} +``` diff --git a/www/content/posts/nspawn.md b/www/content/posts/nspawn.md new file mode 100644 index 0000000..c6add7e --- /dev/null +++ b/www/content/posts/nspawn.md @@ -0,0 +1,206 @@ +--- +title: "Use systemd-nspawn to Create a Development Sandbox" +date: 2025-03-04T23:22:23+08:00 +lastmod: 2025-03-27T17:46:24+08:00 +--- + +*systemd-nspawn* is a great tool for creating development sandboxes. Compared to +other similar technologies, it's lightweight, flexible, and easy to use. In this +blog, I'll present a simple guide to using it. + +<!--more--> + +## Advantages + +I've been using traditional VMs and Docker for creating development +environments. While both work fine, regardless of the performance, they suffer +from being overly isolated. Two big headaches for me are host network sharing in +traditional VMs and the immutability of Docker container ports and mounts. + +*systemd-nspawn* is much more flexible. Every feature can be configured +granularly and dynamically. For example, filesystem sharing can be configured to +work like bind mounts, and network isolation can be disabled entirely, which +exactly solves the two headaches mentioned above. Additionally, being part of +*systemd*, it has the same excellent design as other *systemd* components. + +Debian has a similar powerful tool called *schroot*. It is the official tool for +automatic package building. Unfortunately, it seems to be a tool specific to +Debian. + +## Usage + +*systemd-nspawn* consists of two parts that work together to achieve its VM +functionality: + +1. The program `systemd-nspawn`, which runs other programs in an isolated + environment with user-specified settings. Each running VM is essentially a + group of processes launched via `systemd-nspawn`. +2. Components for defining and managing VMs, possibly utilizing + `systemd-nspawn`. + +*systemd-nspawn* has a user interface similar to *systemd service*: + +- `[name].service` => `[name].nspawn`: Define VMs. + - Should be placed in `/etc/systemd/nspawn/`, where `machinectl` scans for VM + definitions. + - `[name]` serves as the VM's name. Use it to specify the VM when calling + `machinectl`. Note: You'd better use a valid hostname (avoid illegal + characters like `.`) to prevent weird errors. + - The options available roughly mirror `systemd-nspawn`'s CLI arguments, with + some adjustments to better fit VM semantics. + - Isolation-related options are usually prefixed with `Private` (e.g., + `PrivateUsers=`). +- `systemctl` => `machinectl`: Manage VMs. + - `enable`/`disable`: Set whether the VM starts automatically at system boot. + - `start`/`poweroff`/`reboot`/`terminate`/`kill`: Control the VM's running + state. + - `login`/`shell`: Do things inside the VM. + +I'll demonstrate how to create a Debian-based VM on Arch Linux as an example. +You should adjust the commands based on your own situation. + +### Create Root Filesystem + +The root filesystem of a distribution can be created using a special tool from +its package manager. For Debian-based distributions, it's `debootstrap`. If your +OS uses a different package manager ecosystem, the target distribution's one and +its keyrings (which might reside somewhere else) have to be installed first. + +```bash-session +# pacman -S debootstrap debian-archive-keyring ubuntu-keyring +``` + +Regular directories work perfectly as root filesystems, but other directory-like +things should work, too, such as `btrfs` subvolume. + +```bash-session +# btrfs subvolume create /var/lib/machines/[name] +``` + +Now, run `debootstrap` to create a minimal filesystem. Update the command with +the target distribution's codename and one of its mirrors you select. + +```bash-session +# debootstrap --include=dbus,libpam-systemd [codename] \ + /var/lib/machines/[name] [mirror] +``` + +At this point, the filesystem contains only the distribution's essential +packages, much like a base Docker image (e.g., `debian`), so you can customize +it in a similar way. + +### Configure and Customize + +I'll present my personal configuration here as a reference. You can create a new +one based on it or from scratch. + +1. Disable user isolation: `[Exec] PrivateUsers=no` +2. Disable network isolation: `[Network] Private=no` +3. Create a user with the same username, group name, UID and GIDs: should be + done inside the VM. +4. Only bind a subdirectory under *home*: `[Files] Bind=/home/[user]/[subdir]` +5. Set the hostname: `[Exec] Hostname=[hostname]` + +I disable user isolation because it's implemented using the kernel's user +namespace, which adds many inconveniences due to UID/GID mapping. + +So, the final `.nspawn` file is like: + +```systemd +/etc/systemd/nspawn/[name].nspawn +--- +[Exec] +PrivateUsers=no +Hostname=[hostname] + +[Files] +Bind=/home/[user]/[subdir] + +[Network] +Private=no +``` + +If `machinectl` can already start the VM, you can log in to customize it +further. Otherwise, you can use `systemd-nspawn` directly to enter the VM and +run commands inside it. `--resolv-conf=bind-host` binds the host's +`/etc/resolv.conf` file to make the network work. + +```bash-session +# systemd-nspawn --resolv-conf=bind-host -D /var/lib/machines/[name] +``` + +Now, inside the VM, you can do whatever you like. In my configuration, a correct +user must be created manually. + +```bash-session +# apt install locales sudo nano vim less man bash-completion curl wget \ + build-essential git +# dpkg-reconfigure locales + +# useradd -m -G sudo -s /usr/bin/bash [user] +# passwd [user] +``` + +Some setup may need to be done manually, especially those usually handled by the +distribution's installer. + +1. Update `/etc/hostname` with the VM's real hostname. +2. Update `/etc/hosts`. + +```plain +/etc/hosts +--- +127.0.0.1 localhost [hostname] +::1 localhost ip6-localhost ip6-loopback +ff02::1 ip6-allnodes +ff02::2 ip6-allrouters +``` + +**Ubuntu 20.04 specific:** Due to [a bug in +systemd](https://github.com/systemd/systemd/issues/22234), the backport source +has to be added. + +```plain +/etc/apt/sources.list +--- +deb https://mirrors.ustc.edu.cn/ubuntu focal main restricted universe multiverse +deb https://mirrors.ustc.edu.cn/ubuntu/ focal-updates main restricted universe multiverse +deb https://mirrors.ustc.edu.cn/ubuntu/ focal-backports main restricted universe multiverse +deb https://mirrors.ustc.edu.cn/ubuntu/ focal-security main restricted universe multiverse +``` + +### Use + +The following command starts a new shell session for the specified user inside +the VM, where you can run commands and perform tasks. + +```bash-session +# machinectl shell [user]@[name] +``` + +Another way is to use `login` command to enter the *login console*. From there, +you can log in as a user to start a shell session. + +```bash-session +# machinectl login [name] +``` + +To exit a VM session (especially in the *login console*), press `CTRL+]` three +times quickly in a row. + +### Snapshot + +The easiest way to backup/snapshot a VM is to create an archive of the VM's +filesystem. You can use any archive tool you prefer, such as the simple `tar`. +If the VM's filesystem is a `btrfs` subvolume, native `btrfs` snapshots can be +used here. Before creating a snapshot, you should power off the VM to avoid +archiving runtime files. + +```bash-session +# machinectl poweroff [name] +# btrfs subvolume snapshot /var/lib/machines/[name] \ + /var/lib/machines/btrfs-snapshots/[name]/[snapshot-name] +``` + +`machinectl` also provides an *image* feature similar to Docker, though I've +never tried it. Feel free to explore it if you're interested! diff --git a/www/content/posts/pattern-in-cpp.md b/www/content/posts/pattern-in-cpp.md deleted file mode 100644 index be921fd..0000000 --- a/www/content/posts/pattern-in-cpp.md +++ /dev/null @@ -1,25 +0,0 @@ ---- -title: "Pattern in C++" -date: 2022-01-24T15:57:34+08:00 -categories: Coding -tags: - - C++ -description: The secret ingredient of secret ingredient soup is ... ---- - -> The secret ingredient of secret ingredient soup is ... -> Nothing! - -This is a script from Kung Fu Panda, which is one of my favorite film. - -People have been struggling for days to find a pattern in which they can code better. Especially those who use Java. They even wrote a book called "Programming Pattern" (or another name since I might forget the name) to show the common patterns. - -<!--more--> - -I don't mean patterns are bad. However there exists many people who strive to the patterns, stick to the patterns or even get stubborn to patterns. Maybe there exists a way to achieve their goals with some not that patterned code but they don't want to use them at all just because the code is not patterned. - -I love C++. And the pattern of C++ is exactly *NO PATTERN*. You write code in the way that they do the task most effectively and neatly. You don't need to apply a pattern to achieve your goal. You just write your code naturally with the way you are most comfortable with. - -Tools including programming language serve for people but not vice versa. Don't let tools constrain your hands. And when you find tools not convenient, just fix them or make a new one. Just like C++ is evolving all the time. So are all languages. - -The best is code is those that express meanings most clearly and achieve goals most effectively and do nothing with patterns. diff --git a/www/content/posts/use-paddleocr.md b/www/content/posts/use-paddleocr.md index f4eae32..806df41 100644 --- a/www/content/posts/use-paddleocr.md +++ b/www/content/posts/use-paddleocr.md @@ -2,10 +2,10 @@ title: "Use PaddleOCR" date: 2022-11-30T13:25:36+08:00 description: Simple steps to use PaddleOCR. -categories: Coding +categories: coding tags: - AI - - Python + - python - OCR --- |
