阅读视图

发现新文章,点击刷新页面。
🔲 ☆

从 Manjaro 迁移到 Arch Linux

今天我把系统换成了 Arch Linux,用的是 Btrfs 文件系统,套上 LUKS 加密(加密包括 /boot)。由于我已经在虚拟机里面实验过整个过程,所以今天的安装过程非常顺利,一共只用了一两个小时。

背景

前几天用 btrfs-convert 把我的 Manjaro 的文件系统换成了 Btrfs,然后继续开发我的 Btrfs 快照管理工具 dosnap。奇怪的是,在出错的时候(如 panic!)程序不会退出 ,而是直接卡住。这还不是最致命的,过了几秒钟我发现我的 polybar 不见了,然后发现我的家目录里少了一些东西,包括 ~/.config。还好我之前有做快照,可以直接用 rsync 恢复数据。但是在我的一个 Arch Linux 虚拟机中程序如果出错会正确退出。不知道是为什么,可能是 btrfs-convert 的什么 bug。然后就想到用 Arch 虚拟机也有很长时间了,于是打算直接把物理机也换到 Arch Linux 上来。

备份

可以使用 Btrfs 的 send/receive 功能进行备份。注意备份的移动硬盘也需要是 Btrfs 文件系统。先对各个子卷做只读快照,然后对每个快照进行 btrfs send

sudo btrfs send /mnt/_snapshots/${SNAPSHOT_NAME?} | sudo btrfs receive ${EXTERNAL_DRIVE?}

然后再记录一下安装过的软件:

pacman -Qe >${EXTERNAL_DRIVE?}/pacman-qe

安装

启动 archiso,然后调整一下终端字体

setfont ter-v28b

Installation Guide

打开 installation guide,一直做到 Partition the disks 之前。

由于磁盘已经分区,所以不需要再分区了。直接上 LUKS 并格式化为 Btrfs。注意需要用 luks1,因为 GRUB 目前还不支持 LUKS2。

cryptsetup --type luks1 luksFormat /dev/nvme0n1p4
cryptsetup open /dev/nvme0n1p4 archlinux
mkfs.btrfs -L archlinux /dev/mapper/archlinux

然后创建子卷并挂载分区

mount /dev/mapper/archlinux /mnt
btrfs subv create /mnt/@
btrfs subv create /mnt/@home
btrfs subv create /mnt/@opt
btrfs subv create /mnt/@var
umount /mnt

opt='noatime,ssd,space_cache=v2,compress=zstd'
mount -o $opt,subvol=@ /dev/mapper/archlinux /mnt
mkdir /mnt/{efi,var,home,opt}
mount /dev/nvme0n1p1 /mnt/efi
mount -o $opt,subvol=@home /dev/mapper/archlinux /mnt/home
mount -o $opt,subvol=@opt /dev/mapper/archlinux /mnt/opt
mount -o $opt,subvol=@var /dev/mapper/archlinux /mnt/var

/var/log/journal 禁用 CoW:

mkdir -p /mnt/var/log/journal
chattr +C /mnt/var/log/journal

然后从 installation guide 的 Installation 一节开始继续一直做到结尾,记得要在 pacstrap 的时候加上 btrfs-progs

额外的操作

安装到这里还需一些额外的操作。更改 /etc/mkinitcpio.confBINARIES,然后在 HOOKS 中的 filesystems 之前加入 encrypt

BINARIES=(/usr/bin/btrfs)
HOOKS=(base udev autodetect modconf block encrypt filesystems keyboard fsck)

然后重新生成 initramfs

mkinitcpio -P

更改 /etc/default/grub 中的内核命令行,这里我还顺便打开了 cgroup v2。 PARTUUID 可以使用 blkid 命令查看。

GRUB_CMDLINE_LINUX_DEFAULT="loglevel=3 quiet systemd.unified_cgroup_hierarchy=1"
GRUB_CMDLINE_LINUX="cryptdevice=PARTUUID=xxx:archlinux"

同步家目录

新建用户,并从备份中用 rsync 把家目录同步回来:

# run as wang
rsync -a ${EXTERNAL_DRIVE?}/home-snap/wang/* ~
rsync -a ${EXTERNAL_DRIVE?}/home-snap/wang/.* ~

安装软件包

安装我自己常用的软件

cd ~/.dotfiles/weirane-dotfiles-deps
makepkg -si

用下面的命令查看有哪些之前安装过而不在本机上的包,然后选择要安装的包并安装。

comm -23 <(cut -d' ' -f1 ${EXTERNAL_DRIVE?}/pacman-qe | sort) \
         <(pacman -Qq | sort) | less

配置

下面进行一些增加安全性或者便携性的配置。

加密 swap

为防止关机后 swap 中残留明文的内存数据,需要将 swap 加密。我不需要 hibernation,所以参考 ArchWiki,将以下内容加入 /etc/crypttab

swap  PARTUUID=xxx  /dev/urandom  swap,cipher=aes-xts-plain64,size=512

将原来 /etc/fstab 中 swap 的一行改为

/dev/mapper/swap        none            swap            defaults        0 0

Key in initramfs

可以在 initramfs 中放一个 LUKS key,这样在开机的时候就不需要输两次 LUKS 密码了。我一般将 key 放在 /etc 中。注意要调整 key file 和装有 key file 的 initramfs 的权限。

sudo dd bs=512 count=4 if=/dev/urandom of=/path/to/key
sudo cryptsetup luksAddKey /dev/nvme0n1p4 /path/to/key
chmod 000 /path/to/key
chmod -R g-rwx,o-rwx /boot

把 key 加入 /etc/mkinitcpio.conf 中的 FILES

FILES=(/path/to/key)

/etc/default/grub 中的内核命令行,加入 cryptkey=rootfs:/path/to/key

GRUB_CMDLINE_LINUX="cryptdevice=PARTUUID=xxx:archlinux cryptkey=rootfs:/path/to/key"

最后重新生成 initramfs 和 GRUB config

sudo mkinitcpio -P
sudo grub-mkconfig -o /boot/grub/grub.cfg

解决问题

xbacklight

进入图形界面后发现 polybar 中的亮度模块没有显示,xbacklight 命令没有输出。参考 ArchWiki 之后发现应该安装 xf86-video-intel 并将下面的配置写入 /etc/X11/xorg.conf.d/20-xbacklight.conf

Section "Device"
    Identifier  "Intel Graphics"
    Driver      "intel"
    Option      "Backlight"  "intel_backlight"
EndSection

redshift 无法使用 geoclue

运行 redshift 有如下报错

Trying location provider `geoclue2'...
Using provider `geoclue2'.
Using method `randr'.
Waiting for initial location to become available...
Unable to start GeoClue client: GDBus.Error:org.freedesktop.DBus.Error.AccessDenied: 'redshift' disallowed, no agent for UID 1000.
Access to the current location was denied by GeoClue!
Make sure that location services are enabled and that Redshift is permitted
to use location services. See https://github.com/jonls/redshift#faq for more
information.
Unable to get location from provider.

查阅 ArchWiki,将以下内容写入 ~/.config/systemd/user/geoclue-agent.service

[Unit]
Description=redshift needs to get a (geo)clue

[Service]
ExecStart=/usr/lib/geoclue-2.0/demos/agent

[Install]
WantedBy=default.target

运行命令 systemctl --user enable --now geoclue-agent.service 之后就可以使用 redshift 了。

~/.cache 单独分为一个子卷

我现在对我的家目录每两小时进行快照,用了一段时间后发现每个快照都有至少 30 MB 的 exclusive data。比较后发现主要是 ~/.cache 中的数据,所以想把它单独分为一个子卷。

登出当前用户,并在 tty 登陆 root 用户。把 ~/.cache 这个目录空出来,并创建子卷

cd /home/wang
mv .cache .cache2
btrfs subv create /home/wang/.cache

然后把数据复制回来,再恢复权限。

cp -a --reflink .cache2/* .cache
chown wang:wang .cache
rm -r .cache2

分开 ~/.cache 之后每两小时快照的 exclusive data 基本上在 20 MB 之下,效果还可以。

总结

整个过程挺顺利的,现在应该只剩一些之前在 /etc 中的配置没来得及同步了。由于家目录是直接 rsync 过来的,所以所有的数据都还在,家目录中的程序的配置也没有丢失, firefox 等程序也不需要重新登录或者进行其它的配置。

参考

🔲 ☆

将 Caps Lock 映射为 Escape 和 Ctrl

Caps Lock 可能是键盘上最没有用的一个键了,但是它又占据了 home row 的位置。一些人会把它映射成 Escape 或者 Ctrl。但是作为一个 Vim 用户,Escape 和 Ctrl 都是很常用的键。如何让 Caps Lock 在单击的时候是 Escape,和其它键配合的时候是 Ctrl?

TL; DR:总结

  • 2020-11-15 更新:扩充 Xmodmap 一节
  • 2020-04-08 更新:增加了 XCAPE总结
  • 2021-01-27 更新:增加了 TL; DR

之前的配置

这里有一些将 Caps Lock 只映射成 Ctrl 的方法。

Xmodmap

以前 有写过使用 xmodmap 将 Caps Lock 变为 Ctrl 的方法,但是这个方法不能让单击 Caps Lock 时产生 Escape 的效果。做法是将以下内容写入文件,比如存放在 ~/.config/X11/Xmodmap,然后在启动的时候运行 xmodmap ~/.config/X11/Xmodmap。这种方法需要在启动图形界面时和连接新键盘时重新执行以上的命令。

clear lock
clear control
add control = Caps_Lock Control_L Control_R
keycode 66 = Control_L Control_L Control_L Control_L

setxkbmap 命令

使用下面的命令可将 Caps Lock 映射成 Ctrl,和 Xmodmap 一样需要在启动图形界面时和连接新键盘时重新运行命令。

setxkbmap -option ctrl:nocaps

hwdb

前两个方法的问题之一是它只对 X 有效,到了 tty 中就不起作用了。有一个更加底层的方法是使用 hwdb。参考 Arch Wiki,对笔记本内置的键盘可以将以下的内容写入 /etc/udev/hwdb.d/xxx.hwdb

evdev:atkbd:dmi:*
 KEYBOARD_KEY_3a=leftctrl  # Caps Lock down as Left Ctrl

运行以下命令生效

sudo systemd-hwdb update
sudo udevadm trigger

如果 hwdb 可以对连续的几个 scancode 进行设置的话也许可以达成映射 Caps Lock 为 Escape 和 Ctrl 的目标,但是好像并不行,reddit 上有一个 帖子 也一直没有人给出解决方法。

可行的方法

Interception Tool

使用 Interception Tool 配合插件 caps2esc。安装这两个 AUR 包或者去主页上查看安装方法。

yay -S interception-tools interception-caps2esc

将以下内容写入 /etc/udevmon.yaml

- JOB: "intercept -g $DEVNODE | caps2esc | uinput -d $DEVNODE"
  DEVICE:
    EVENTS:
      EV_KEY: [KEY_CAPSLOCK, KEY_ESC]

运行并自动启动 udevmonsudo systemctl enable --now udevmon

如此配置之后 Caps Lock 在单击的时候会变成 Escape,做为组合键的时候是 Ctrl。同时原来的 Escape 键变成了 Caps Lock。

但是我不想让 Escape 映射成 Caps Lock,研究了 caps2esc 的源码后发现只要将替换 ESC 的 code 那两行删除即可,如下。

diff --git a/caps2esc.c b/caps2esc.c
index e9e29b6..d3641f2 100644
--- a/caps2esc.c
+++ b/caps2esc.c
@@ -77,8 +77,6 @@ int main(void) {
             continue;
         }
 
-        if (input.code == KEY_ESC)
-            input.code = KEY_CAPSLOCK;
         write_event(&input);
     }
 }

安装新编译出来的 caps2escsudo systemctl restart udevmon 即可。

这里注意一定不要把下面的 write_event(&input); 删掉了,否则会让所有的键都没反应 ,重启也没有用,因为 udevmon 会自动启动。最后得想办法删掉 /etc/systemd/system/multi-user.target.wants/udevmon.service 以取消自动启动 udevmon,比如用 Live USB 或者 SSH 到主机。(不要问我是怎么知道的)

此时如果需要触发 Caps Lock 键(比如 Caps Lock 不知为什么被打开了),只能先将 udevmon 停止再按 Caps Lock。为了方便我给 caps2esc 加了一个 signal handler,当收到 SIGUSR1 的时候触发 Caps Lock,这样需要的时候可以直接 sudo killall -USR1 caps2esc源代码 放在了 GitHub 上,还有一个对应的 AUR 包 intercept-caps2esc-nocaps-git

XCAPE

果然每次写完一篇博客后都会发现一些其它的解决方案

如果对在 tty 中的映射没有要求的话,还可以使用 XCAPE 工具。XCAPE 的主要功能是对 modifier key 按下后直接弹起的动作进行映射。可以先使用 之前 说的方法映射 Caps Lock 为 Ctrl,再使用 XCAPE 将按下 Ctrl 再直接弹起映射为 Escape:

xcape -e 'Control_L=Escape'

启动图形界面时运行此命令。

总结

  • 只想在 X 中映射 Caps Lock 到 Ctrl 和 Escape:使用 Xmodmap 或者 setxkbmap 加上 XCAPE
  • 在 tty 中也映射:使用 interception tools
  • 在 X 中映射到 Ctrl 和 Escape,tty 中只映射到 Ctrl:使用 hwdb 和 XCAPE
❌