/ˌoʊpənˈsuːzə/

Desktop Installation

DVD 方式安装

  • 安装系统方式选择 DVD 方式安装。使用其他方式安装系统需要耗费比其他安装方式更多的时间和精力,除非必要,建议优先使用离线的 DVD 镜像进行系统安装。这里推荐滚动更新的 openSUSE Tumbleweed。
  • 最好是到官网下载 openSUSE 风滚草的 ISO 文件。因为 openSUSE 官网才会第一时间提供最新版风滚草 ISO 映像文件,国内的很多镜像站一般不会第一时间就同步过来,这样就免除在安装好后还需要更新系统的步骤。
  • 语言选择 English,因为 Linux 需要经常使用 Terminal,中文家目录是很不方便的。
  • Network 可以设置 static hostname。
  • System Role 选择 Desktop with KDE Plasma,openSUSE 的 KDE 是最好的。
  • 分区 选择默认的 btrfs 文件系统,可通过 Guided setup 进行多样化设置,比如 root 用 btrfs,home 用 ext4,单独为 swap 建立一个分区之类的。
  • Clock and time zone 记得使用 UTC 和 NTP。
  • 在最后的部分,可以点击 Software,取消安装 Office Software、Games、KDE PIM 模组。
  • 在安装好后,先进桌面进行初始化,如果不进直接在 TTY 中恢复备份,就不会创建 Desktop、Download 等目录其他配置。

镜像源

国内镜像

我们官方的态度是不鼓励直接使用镜像的。

因为比起「其它」发行版,我们 openSUSE 的技术力量比较强,开发了两个东西。

一个叫做 Metalink,意思是这个格式(BT、Megalink 磁力链一样的格式)可以自动从 BT/FTP/HTTP 同时下载。

另一个叫做 MirrorBrain,意思是我把所有的镜像地址隐藏起来,只暴露出一个中央服务器,所有人只需使用这个中央服务器(download.opensuse.org ),它会根据你的 IP 地理位置为你分配一个离你最近的镜像,但是在你那边显示的依旧是来自 download.opensuse.org。而如何分配是根据镜像管理员和中央服务器管理员当初的协定来确定的,比如镜像每月能够承受的流量、所愿意扮演的角色(是区域中心、地标式的镜像比如北交大、中科大,还是小镜像)等。如果你是一名光荣的 Qt 开发者,那你应该早就有所感觉了,因为 Qt 项目的下载就是用的我们开发的 MirrorBrain 技术。

而根据 openSUSE 软件源的构造,所有的 RPM 包都是从镜像获得的,所有的 metadata(元数据)都是从主镜像(位于德国)获得的,所以你源刷新的慢,只能证明你被我们光荣伟大的放火长城拖住了,而不能证明 openSUSE 项目有错,也代表不了你下载 RPM 包时的速度。

  1. 常见的科学上网手法。但是这样做比较浪费,因为我墙是大小姐脾气,时撞时不撞。
  2. 关掉自动刷新,用 cron 定时刷新或 sudo zypper ref 手动刷新,这样就避免了「越着急越装不上软件」的窘境(具体教学论坛里就有,多搜索),因为这时的流量都是来自国内。
  3. 使用镜像,这样完全不添加 download.opensuse.org 就不会从德国下东西了。

具体选择哪一种就看你究竟是刷新慢还是下载慢了。使用镜像也不是没有缺点的:

  1. 镜像有延迟,6 个小时 ;
  2. 镜像不能面面俱到,比如你添加 home:opensuse_zh 源,OBS home 源是很少有镜像的,单一源慢一样让你改用了镜像都感觉不出来快。
  3. 这个帖子让我意识到,有些人是镜像源也加,主源也加,完全不知道镜像是什么意思(它们的内容是相同的),所以加了镜像刷新依然不会快,因为你主源还开着。所以特意说明下,使用镜像这种方法是非黑即白的,你要用镜像所有启用了刷新的源都要用镜像,不然没有意义。
  4. 镜像是没有容错能力的,也就是说比如你用北交大镜像,每次开十几大他们学校都会封外网,那你隔几年的三月份就无法使用一次。

另外前面说过了,自动根据 IP 地理位置分配的原理一是 IP 的真实地理位置,你挂 VPS 慢了别怪别人 ; 二是人家有协定。所以有时候你下载 RPM 慢非常有可能是你被中转到了地理位置较远的服务器,但理论上这恰好证明了离你较近的镜像现在没有能力服务你(过载了或无法访问)。

但在国内这个情况很乱:把自己申报为官方镜像的镜像太少,只有:北交、中科大、搜狐、华中科大。地下源太多了,比如清华、网易、浙大这些都没有申报官方镜像。所以明明有近的给你中转到远的非常正常,因为中央服务器不知道有近的。

更换镜像

可以使用由 openSUSE 社区开发的测速工具查找快速的镜像站。更好的选择是在 Mirrors Report 中选择 repo 更新最及时的官方镜像。一般 TUNA 与 USTC 更新及时、下载速度快。

用官方源下载元信息非常慢,用代理又会导致下载 RPM 包用国外的镜像,非常麻烦,因此我选择完全使用 TUNA Mirror,下载元信息与 RPM 包都用镜像。

$ sudo zypper mr -da
$ sudo zypper ar -cfg 'https://mirrors.tuna.tsinghua.edu.cn/opensuse/tumbleweed/repo/oss/' tuna-oss
$ sudo zypper ar -cfg 'https://mirrors.tuna.tsinghua.edu.cn/opensuse/tumbleweed/repo/non-oss/' tuna-non-oss
$ sudo zypper ref

更新 Tumbleweed

无论怎样,下面的内容将完成升级:

  1. 退出你的桌面环境,在登录管理器中按 CTRL + ALT + F1 进入内核终端界面。

    openSUSE 升级系统的方法:这样做的目的是因为,系统更新的时候会更新到 konsole 和 gnome terminal,这是它们就会无法正常工作,就突然退出,这时肯定无法再打开它们。如果学习 Windows 的臭习惯的话,重启!恭喜你,进不去了,系统升级一半没有一个系统是进得去的。新手一般就重装或者换发行版了。但是这是你的逻辑性错误,没有人为你买单。

  2. 以 root 的身份登录。

    openSUSE 的 root 密码与安装系统时设置的管理员账户密码一样。

  3. 输入命令 zypper ref && zypper dup

    更新 openSUSE Tumbleweed 的正确姿势:滚动更新」的每一个更新快照(snapshot)都相当于一次系统版本升级。使用选项 no-allow-vendor-change 的目的在于防止因为有除了 opensuse-tumbleweed-* 之外的源存在而破坏了 openSUSE Tumbleweed 系统;而使用 dup(dist-upgrade) 而不是 up(update)的好处在于,zypper dist-upgrade 会在升级过程中清除不再使用的软件包,而 zypper update 则不会,对于 openSUSE Tumbleweed 这样的滚动更新发行版来说,将过期的软件包保留在系统中也是可能会造成很大问题的。

    在 openSUSE Tumbleweed 20170708 快照中,libzypp 从 16.12.0 升级到 16.13.0,针对 Tumbleweed 修改了 /etc/zypp/zypp.conf 的默认配置,将 zypper dup 默认设置为开启 --no-allow-vendor-change 选项。

  4. 处理好任何冲突,然后同意升级。

  5. 当升级完成后,输入命令:reboot

软件管理

更新/刷新进程被占用

在 System Tray Setting 里面关闭 Software Updates 的通知。

如果你不需要自动更新,或者不需要 Packagekit 本身,你首先可以考虑:

$ sudo systemctl mask packagekit.service #屏蔽 Packagekit 服务

取消推荐的软件包 & 删除模组

打开 YaST ,点击 软件管理 ,再点击左上角的 依赖项 ,取消勾选 安装被推荐的软件包 。这样你的电脑就不会在某次更新后出现一些不是你主动安装的软件包。

软件管理 页面,点击 视图,选择 模组 ,然后你就能看到按模组分类的包。例如你可以在此页面直接用鼠标右键单击 游戏 ,选择 不安装卸载,卸载全部的预装的 KDE/Gnome 游戏包。

Packman

什么是 Packman ?

openSUSE 的 Packman 是 Package man 的缩写。意即指一群打包狂组成的团体。他们在尊重并重视版权的基础上做一些规避专利的事。总之,他们想要自由打包从多媒体到大型软件到游戏到甚至是自己的回收站的所有内容。

Packman 和 openSUSE 的关系

Packman 不隶属于任何 openSUSE 官方,是独立于 openSUSE 社区之外的社区,只是基于 openSUSE 打给 openSUSE 用的软件包。注意 openSUSE 社区也是官方,同样有在专利法最为严苛的美国和欧洲注册,这也是为什么 OBS 不能打包专利软件的原因,另一个原因是 OBS 的服务器坐落于德国诺伦堡。

Packman 的资源来自于成员捐献,不能和 openSUSE 官方有任何的联系,也就是说即使是 SuSE 的捐献,也要放弃一切权利。不能像社区董事会那样,主席要由 SuSE 指定,一般是 SuSE 员工。

Packman 欢迎大学和社区为它做镜像

Packman 收纳什么样的软件 ?

由于英文的 free 很有迷惑性(大部分外国人喜欢用法语 Libre,也就是自由):

  • 这里的自由,仍然不包括商业和私有软件,版权产品应该尊重他们自有的分发渠道。也就是说,这里仍然不做盗版,也不做免费使用的商业软件。不规避版权,只规避专利。版权同样是保护 Linux 下的开源作品不被盗版的力量,而专利则是大公司用来牟利的工具。
  • 这里只接纳由于或有专利纠纷而不能存在于官方构建服务中的软件。比如 FFMPEG,MPLAYER,MP3, AMULE。和依赖它们的软件。以及可以自由分发的软件,并且愿意允许从源代码编译。

也就是说,大部分时候这里的软件都是 FOSS/LOSS (自由和开源软件),而不是免费软件。而且是存在或有专利纠纷的软件,想想看什么软件最容易发生专利纠纷呢? 多媒体。于是 Packman 里有那么多多媒体软件也就不奇怪了。

另外 Packman 还允许两类软件:发行版中长期不更新的软件的最新版,和发行版中没有的软件。但这是 FTP 做源的时代延续下来的。目前这两类软件都建议走 OBS 流程来做,因为 OBS 的服务器比 Packman 的多快好省。

启用 Packman 源

国内可用的 Packman 镜像列表:Packman/镜像列表

openSUSE Tumbleweed 用户:

$ sudo zypper ar -cfp 90 'https://mirrors.tuna.tsinghua.edu.cn/packman/suse/openSUSE_Tumbleweed/' packman
$ sudo zypper ref
Multimedia Codecs

openSUSE 默认是没有部分多媒体编解码器的,包括家喻户晓的 MP3、AVI 等。这是因为它们是受限媒体格式。具体解释见openSUSE 编解码器一键安装、常见编解码器对应软件包/源说明、及版权须知

通过 Packman 安装解码器:如果不使用 VLC 可以省略 vlc-codecs

$ sudo zypper rm vlc
$ sudo zypper dist-upgrade --from packman --allow-vendor-change
$ sudo zypper in --from packman ffmpeg gstreamer-plugins-{good,bad,ugly,libav} libavcodec-full

或者通过 opi 安装:

$ sudo zypper in opi && opi codecs

or, In order to install the H264/AVC support on your system, type in:

$ sudo zypper in x264 libx265-130 libx264-148

OBS Package Installer

如果你想在终端直接查找来自 OBS 的软件包,你可以先安装 opi

$ sudo zypper in opi

然后输入你想要查找的软件包的名称,例如你要安装 qbittorrent enhanced edition ,你可以:

$ opi qbittorrent

中文社区源

openSUSE 中文社区的开发者们为用户构建、打包和收录一些发起自中文 Linux 圈子的软件或中文 Linux 圈子常用的软件。详见:

安装软件包

常用软件

$ sudo zypper in -y --no-recommends \
android-tools android-tools-bash-completion \
aria2 \
goldendict \
git \
unrar \
proxychains-ng \
kdeconnect-kde \
tree \
qemu-kvm qemu-audio-pa samba qemu-ui-gtk qemu-hw-display-qxl qemu-hw-usb-host \
google-noto-sans-cjk-fonts \
  • 如果不安装 android-tools-bash-completion,就补全 /sdcard 下的路径。
  • 在 openSUSE 下,qemu-kvm 默认使用 vnc,且默认不安装 qemu-audio-pa,可安装 qemu-ui-gtkqemu-hw-display-qxl 使其支持 -display gtk-vga qxl 参数,并使用 -vnc none 关闭 vnc。qemu-hw-usb-host 用于 USB 直通。
  • 如果系统语言是 English 的话,默认也不会安装 CJK 字体 google-noto-sans-cjk-fonts 的。
  • 如果出现 File 'xxx.rpm' not found on medium 'xxx',则需要 zypper ref,openSUSE 更新很频繁的。

输入法

在Yast中安装第二语言,就会自动安装fcitx并添加中文支持,但是这种方案安装的东西很多。

Fcitx5
$ sudo zypper in -y --recommends fcitx5 fcitx5-chinese-addons

设置主题:Setting -> Location -> input method -> Configure addons -> Classic user interface -> Theme.

输入法最好使用 –recommends,否则会遇到很多麻烦,比如要手动安装 kcm_fcitx5,第三方软件(Typora、Chrome)不能使用中文等。一些相关信息如下:

$ cat /etc/xdg/autostart/org.fcitx.Fcitx5.desktop
$ cat /usr/etc/X11/xim.d/fcitx5 
#make sure set these vars before dbus-launch
export LC_CTYPE=$LANG
export XMODIFIERS="@im=fcitx5"
export GTK_IM_MODULE=fcitx5
export QT_IM_SWITCHER=imsw-multi
export QT_IM_MODULE=fcitx5
...

打包信息详见openSUSE:Factory/fcitx5

词库

Fcitx 的 Libpinyin 可以直接在线导入搜狗细胞词库。不需要安装sougou输入法。

需要安装 fcitx-pinyin-tools/fcitx-table-tools 这两个包,以添加处理词库的工具

$ sudo zypper in fcitx-pinyin-tools fcitx-table-tools

词库少了的话,也不好用,但是一次只能导入一个细胞词库。网上可以找到比较全的词库包。

通过 7zr 解压过后将所有 txt 词库拷贝到 ~/.config/fcitx/libpinyin/importdict 即可。

$ 7zr x txt.7z

cloudpinyin

根据文档,可以使用 libpinyin + cloudpinyin,哪怕不用导入词典,依旧很好用。果然,还是云词库的力量强大。

$ sudo zypper in fcitx-cloudpinyin

默认的云输入引擎是 Google ,国内直接访问很不流畅,你可以打开输入法的配置,点击 Addon Config,找到 Cloud Pinyin ,点击右侧的设置,在弹出的窗口中,将 Google 替换为 Baidu 。

ibus
$ sudo zypper in ibus ibus-rime
$ vim .bashrc
export GTK_IM_MODULE=ibus
export XMODIFIERS=@im=ibus
export QT_IM_MODULE=ibus
$ ibus-daemon -x -d

KDE Wallet

在每次重装或者配置桌面后kdewallet总是在登陆系统之后提示输入密码,虽然在输入密码后能够继续正常使用,但是每次登陆系统都需要输入一次密码还是很烦人的。

出现的原因:

在重新配置桌面或者重装系统之后KDE Wallet所需要的一些必备需要依赖组件未能找到,所以导致不能正确运行KDE Wallet,所以只要安装其所需的组件即可。而其所需的但是未能自动安装的依赖组件正是 pam_kwallet,kwallet-pam 与 GnuPG keys 不兼容,所以 KDE Wallet 必须使用 blowfish 加密方式。

解决方案 :

安装缺失的组件

$ sudo zypper in -y pam_kwallet

为了保险起见,查看个人目录下是否存在~/.kde4/share/apps/kwallet文件夹,如果存在则将其删除或者重命名以避免出现冲突,并且还需要确定使用的钱包名为kdewallet并且密码为当前用户的密码。

如此便可完全正常使用KDE Wallet

解决方案参考arch wikiKDE Wallet小节中。

Google Chrome

$ sudo zypper ar -cfg 'https://dl.google.com/linux/chrome/rpm/stable/x86_64' google-chrome
$ sudo rpm --import https://dl.google.com/linux/linux_signing_key.pub
$ sudo zypper in -y google-chrome-stable

NVIDIA

注意:1、NVIDIA 使用的是 NVIDIA 官方源,而如果软件使用的是 mirror 的话,由于同步延迟,导致 kernel 版本不一致,从而导致 nvidia 安装失败,这个时候要么切换同步更及时的源,要么等一会儿再试;2、在安装 Nvidia 的时候只安装 Nvidia,比如先安装 zfs 再安装 Nvidia,如果 zfs 安装有问题(Module zfs not found in directory),导致 dracut -f 报错,nivdia 模块就不会自动加载,但是手动加载重新登陆后也是可以正常运行的。

有两种为英伟达(NVIDIA)显卡提供的驱动:

  • 为 NVIDIA 硬件提供的自由开源的驱动名叫 nouveau。
  • 来自 NVIDIA 厂商自己的驱动名为 nvidia,但由于许可证问题,它不能直接被集成进入 openSUSE

如果你没有特别的需求,NVIDIA 的闭源驱动不是必须安装的。持有 NVIDIA 独立显卡之类厂商只提供闭源驱动的硬件的 Tumbleweed 用户请不要过于频繁地更新系统,闭源驱动可能会因为内核版本太新缺乏适配而崩溃。

安装

将你的系统更新至最新的版本。

$ sudo zypper dup

添加 Nvdia 软件源

$ sudo zypper ar -cfg  'https://download.nvidia.com/opensuse/tumbleweed' nvidia

获取架构信息

$ sudo hwinfo --gfxcard | grep Model

确定安装的驱动类型

$ zypper se -s nvidia

要利用 OpenGL 加速,你必须安装一个附加包,选择与驱动程序对应的包:

$ sudo zypper in -ly nvidia-video-G06 nvidia-gl-G06 nvidia-compute-utils-G06
  • -l, –auto-agree-with-licenses

最后,重启电脑确认是否加载

$ sudo lsmod | grep nvidia 
$ nvidia-smi

卸载

$ sudo zypper rm nvidia-video-G06 nvidia-gl-G06
$ sudo dracut -f
画面撕裂

出现此种情况,你必须打开 “PRIME同步” 功能:

  1. 创建文件

    $ echo "options nvidia_drm modeset=1 " | sudo tee /etc/modprobe.d/nvidia-drm-nomodeset.conf 
    
  2. 执行代码:

    $ sudo dracut -f
    
  3. 重启

注意: 在某些情况下,修改此配置可能会导致图形界面无法进入,若出现此情况,请进入重启后进入恢复模式,执行 sudo rm /etc/modprobe.d/nvidia-drm-nomodeset.conf ,然后执行 dracut -f ,然后重启

OpenZFS

  • openSUSE Tumbleweed

    $ sudo zypper ar -cfg 'https://download.opensuse.org/repositories/filesystems/openSUSE_Tumbleweed/' filesystems
    $ sudo zypper ref
    $ sudo zypper in -y zfs zfs-kmp-default
    

包 zfs 只提供用户空间(userspace),如命令 zfs、zpool 之类的,包 zfs-kmp-default 中的 kmp 即 Kernel Module Package,CentOS Fedora openSUSE 的 kmp 包都是这个意思,其提供 zfs.ko,如果没装,会报错 Module zfs not found in directory

一般情况下,一个没见过的软件包,可在 software.opensuse.org 上搜,然后点那个查看边上的 Sub-Packages,这样很容易发现漏了什么;如果子软件包名不足以让我猜出这个子包的作用,可点 View => openSUSE Tumbleweed(发行版) => 包名,这样跳到 OBS 去看 specfile,里面关于子包的 summary 和 description 会告诉我一切。

zfs-kmp-default 完整包名如 zfs-kmp-default-2.1.9_k6.1.7_1-1.5.x86_64,其中 k6.1.7_1 即对应内核 6.1.7-1,如果内核版本不对应,openSUSE 是无法安装的。这个时候可以找找社区软件包下面的,肯定很多人为了绕过这个问题选择了自己 fork 一下,在 obs 对应的页面点击 Derived Packages 即可在下拉列表中选择一个,进去后点击 Repositories => Publish Flag => openSUSE_Tumbleweed(发行版名称)即可查看详细包名。

装入 NTFS 分区

  1. 安装 ntfs-3g

    sudo zypper in ntfs-3g
    
  2. 创建一个要充当安装点的目录,如 ~/mounts/windows

    mkdir ~/mounts/windows
    
  3. 确定所需的 Windows 分区。

    sudo fdisk -l
    
  4. 以读写模式装入分区。使用相应的 Windows 分区替换占位符 DEVICE

    ntfs-3g /dev/DEVICE MOUNT POINT
    

    要在只读模式下使用 Windows 分区,请追加 -o ro

    ntfs-3g /dev/DEVICE MOUNT POINT -o ro
    

    ntfs-3g 命令使用当前用户 (UID) 和组 (GID) 装入给定设备。如果要为其他用户设置写权限,请使用命令 id USER 获取 UID 和 GID 值的输出。设置方式:

    id usernamentfs-3g /dev/DEVICE MOUNT POINT -o uid=1000,gid=100
    
  5. 要卸载资源,请运行 fusermount -u 安装点

ntfs-3g 与 ntfs3

Linux Kernel 5.15 合并了 Paragon 提供的 NTFS3 内核驱动, 拥有更高的性能和更多的特性

总结:内核驱动开销变低, 读取性能有所提升,写入性能大幅提升,不考虑硬盘速度的话,写入速度接近10x

Audacious

一个设计简洁,功能强大,支持多种格式的无损播放器。

$ sudo zypper in audacious

YesPlayMusic

0.4.5版本不能在openSUSE Tumbleweed上正常运行

不过我挺好奇是什么造成了能够用这种方法解决的bug

nodejs中的相关函数: listen(port: number, hostname: string, callback?: () => void): http.Server;

以下摘自archlinux手册

•If the kernel commandline parameter systemd.hostname= specifies a valid hostname, systemd(1) will use it to set the hostname during early boot, see kernel-command-line(7), •Otherwise, the “static” hostname specified by /etc/hostname as described above will be used.

the static hostname has higher priority than a transient hostname, which has higher priority than the fallback hostname

看相关函数的签名,nodejs依赖hostname来解析ip地址,由于设置了静态主机名,所以使用了写入在/etc/hostname中的静态主机名

于是在/etc/hosts中需要一条解析主机名的记录,一般在/etc/hosts中都会有这样一条:

127.0.0.1 myhostname.localdomain myhostname

对应的含义为ip地址 主机名 主机别名

结合以上信息,该BUG产生的原因应该只是由于无法解析主机名到对应的ip地址,于是nodejs无法启动对应的server

ypm本体可以启动的原因是直接硬编码了127.0.0.1,没有依赖于hostname行为

KDE Settings

trash-cli

rm -rf 文件会彻底消失掉。为了避免误操作,有人写了一个替代品 trash-cli ,从命令行里面删除的时候移动到回收站,也就是 trash:/

不过 trash-cli 有点臃肿和重复,kde 的 kioclient5 可以做一样的事情

kioclient5 move <filename> trash:/
# 这里可以用文件通配符: 删除所有 .jpg 文件
kioclient5 move *.jpg trash:/ 

可以在 .bashrc 里面加入这个命令来放心地删除文件

function krm(){
    kioclient5 move "$@" trash:/
}

liberate Super Key

为了避免快捷键冲突,我给所有软件 (比如 Emacs) 添加自定义快捷键都会用 SuperKey(Microsoft 叫 WinKey,Appple 叫 CommandKey)来弄。这时候就需要禁用 SuperKey 启动开始菜单来防止误操作。

kwriteconfig5 --file kwinrc --group ModifierOnlyShortcuts --key Meta ""
# 重载配置
qdbus org.kde.KWin /KWin reconfigure

kwriteconfig5 那条命令的实际作用是在~/.config/kwinrc 里面修改了这部分

[ModifierOnlyShortcuts]
Meta=

如果你想迁移你的 KDE 设置,可以把所用自定义的设置都用脚本来表示,比如说禁用键盘上的锁屏键

# 修改 ~/.config/kglobalshortcutsrc 里面 [ksmserver] 中 Lock Session= 的值为 ",,Lock Session"
kwriteconfig5 --file kglobalshortcutsrc --group ksmserver --key "Lock Session" ",,Lock Session"

Custom Context Menu

KDE 可以添加自定义的右键菜单,比如说我自用的通过 Inkscape.svg 转换成 .eps( LaTeX 插入 .eps 方便一些)

把如下的内容丢进 ~/.local/share/kservices5/ServiceMenus/svg2eps.desktop 即可。

[Desktop Entry]
Type=Service
ServiceTypes=KonqPopupMenu/Plugin
MimeType=image/svg+xml
Actions=svg2eps
Icon=view-refresh

[Desktop Action svg2eps]
Name=convert svg to eps
Icon=view-refresh
Exec=inkscape -D "%f" --export-type=eps

唯一重点的一行是 Exec=

原始的命令是 inkscape -D <filename> --export-type=eps,然后把 <filename>换成 %f, Dolphin 就会在从右键使用的时候自动传入目标文件。(大写的版本%F会传入一组文件)。

具体的写法在 Freedesktop Desktop Entry Specification-> The Exec key 里面。

MimeType= 是匹配文件格式,可以用 file --mime-type -b <filename> 来获取,或者从 freedesktop/xdg-shared-mime-info 里面查

你可能注意到,右键菜单里面的格式,用的和 launcher(开始菜单)用的是用样的格式 .desktop

如果仔细考虑一下,他们本质上是没有区别的,只不过一个从 launcher 里面打开,另一个从右键呼出。不过通过右键打开的,可以获取一些文件和目录的信息。

详细的教程 https://develop.kde.org/docs/extend/dolphin/service-menus/

长命令通知

如果一个命令需要运行的特别特别久,可以在命令后面加上 && notify-send <message>"

比如 ls && notify-send "finished at $(date +%c)"

不过这个通知一会就会消失,可以在设置里面,把 low priority 的通知设置成 show in history

这个同时还可以插入图片,想知道可以搜以下 KNotify/Knotifications 的 API…

Command Palette

自从某一个版本以后,用 KDE 框架写的软件都” 自动 “地获得了一个命令面板功能 Ctrl+Alt+i,正式的名称应该是 KCommandBar。

这里有两个好玩的:

  • okular ” 自动 “地获得搜索最近打开文件的能力

  • Kate 可以更加方便地调用外部程序(类似于 Kakoune 那种几乎完全借助外部程序处理文档编辑的操作)。

    需要做的就是从菜单栏的 Tools -> External Tools -> Configure 里面添加新的外部程序,比如 google 搜索选定的文本。

    也可以这样操作来安装这个 google 搜索:

    echo "[General]
    actionName=externaltool_GoogleSearch
    arguments=https://www.google.com/search?q=%{Document:Selection:Text}
    executable=/usr/bin/xdg-open
    icon=plasma-search
    name=GoogleSearch
    output=Ignore
    reload=false
    save=None" > ~/.config/kate/externaltools/googlesearch 
    

    然后这样搜索一段选定的文本了

Reset to default panel

Right click on the desktop/screen, choose Add New Panel from the pop-up menu, then maybe Default Panel.

ksetwallpaper.py

def setwallpaper(filepath, plugin='org.kde.image'):
    jscript = """
    var allDesktops = desktops();
    print (allDesktops);
    for (i=0;i<allDesktops.length;i++) {
        d = allDesktops[i];
        d.wallpaperPlugin = "%s";
        d.currentConfigGroup = Array("Wallpaper", "%s", "General");
        d.writeConfig("Image", "file://%s")
    }
    """
    bus = dbus.SessionBus()
    plasma = dbus.Interface(bus.get_object(
        'org.kde.plasmashell', '/PlasmaShell'), dbus_interface='org.kde.PlasmaShell')
    plasma.evaluateScript(jscript % (plugin, plugin, filepath))

def set_lockscreen_wallpaper(filepath,plugin='org.kde.image'):
    if os.path.exists(SCREEN_LOCK_CONFIG):
        new_data=[]
        with open(SCREEN_LOCK_CONFIG, "r") as kscreenlockerrc:
            new_data = kscreenlockerrc.readlines()
            is_wallpaper_section=False
            for num,line in enumerate(new_data,1):
                if "[Greeter][Wallpaper]["+plugin+"][General]" in line:
                    is_wallpaper_section = True
                if "Image=" in line and is_wallpaper_section:
                    new_data[num-1] = "Image="+filepath+"\n"
                    break

        with open(SCREEN_LOCK_CONFIG, "w") as kscreenlockerrc:
            kscreenlockerrc.writelines(new_data)

如果想用 set_lockscreen_wallpaper,必须先到 System Settings > Workspace Behavior > Screen Locking 设置默认的 Wallpaper,这样才能使 is_wallpaper_section 为 True。

Locales of SDDM

在使用 KDE 的时候,在设置里将语言改为英文,会发现 SSDM 依旧是中文日期,原因是:The SDDM is following the system locales.

如此,参考 Locale - Arch Wiki,修改 /etc/locale.conf 为如下:

LANG=en_US.UTF-8
+ LC_TIME=C.UTF-8

locale 结果如下:

LANG=en_US.UTF-8
LC_CTYPE=en_US.UTF-8
LC_NUMERIC="en_US.UTF-8"
LC_TIME=C.UTF-8
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

任务栏透明化

Go to System Settings | Window Management | Window Rules. Press New… button. Give some description to the new rule, Dock Transparency, for example. Then select only Dock (panel) in “Window type” field.

之后在 Appearance & Fixes 中调整 opacity。

主题设置

不是我喜欢黑暗主题,而是热门的好看的主题都是黑暗主题。所以尝试如下:

  • 全局黑暗主题为 Sweet
  • chrome 黑暗主题
    • 系统设置 Theme 使用 GTK+,可以使标题栏,设置菜单栏为黑暗,但是网页、设置页为白色。
    • Chrome 黑暗模式:在网址栏输入 chrome://flags/#enable-force-dark,启用。可以使设置页面黑暗,网页黑暗,但是进入 segmentfault,你会发现 segment 不见了(即表现不好)。
    • 安装 dark reader 插件。可以使网页黑暗,比 chrome 自带表现要好。但是打开新页面时,还是有短暂的白色。
  • Firefox 黑暗主题
    • 设置页的颜色会与系统一致,也就是与 chrome 相反。
    • firefox theme 会改变标题栏、设置菜单栏颜色。

实际上你会发现,无法达到一致的黑暗,反而使得眼睛不舒服,所以我放弃了黑暗主题。

亮色混合主题:

  • Global Theme 为 openSUSE
  • Plasma 为 Edna-light
  • Window Decorations 为 Edna-light
  • Font 为 Source Hans Sans CN 和 Jet Brains Moon
  • Icon 为 Papirus
  • SSDM Theme 为 chili for plasma
  • kconsole 主题为 sweet
  • 开始改为 application dashboard

实际你会发现,混合主题没有一个单独主题搭配的那么协调。

窗体内容亮色,其他部分为黑暗,即标准主题:

  • 全局主题 Sweet
  • Colors 为 Breeze,使得 window 内容为亮色
  • Window Decorations 为 sweet-dark-transparent,设置标题栏
  • Icon 为 Papirus
  • SSDM Theme 为 sweet
  • fcitx 为 dartmouth。

感觉可以。

Desktop Effects:

  • Magic Lamp 400ms
  • Wobbly Windows

不如不要。

Switching desktops

Q: Disabling mouse scroll-wheel switching between virtual desktops

A: Right-click the desktop -> Configure Desktop and Wallpaper… -> Mouse actions -> “vertical scrollwheel: Standard Menu”

Qkular: Dark Mode

Configure Qkular => Accessibility => Color mode => Invert color

Spectacle: clipboard

Configure => General => after taking a screenshot => Copy image to clipboard

Konsole

Window size

不需要记住每次调整的窗口大小:Setting => Configure Konsole => Remember window size

Apperence

Built-in Profile 是 Read-only 的,需要建立一个新的 Profile 才能设置 Appearance、改变字体之类的,也只有在建立新的 Profile 后,才能在 Settings 中找到 Edit Current Profile…。

Brightness

有一天屏幕突然很黑,找了一下在如下地方设置:

System Settings => Power Management => Energy Saving => Screen Brightness

You can also use krunner to set the brightness. Launch it with Alt+Space and type screen brightness 60 to set the brightness level to 60.

Vision (eyesight): What is the ideal computer screen brightness level for eye health?

The brightness of your display should not be left at the default setting but adjusted according to the brightness of the room where it’s installed. This can greatly reduce the strain on your eyes. For example, in an office with a normal brightness of 300-500 lux, the display brightness should be adjusted to around 100-150 cd/m2.

But when you give specific numbers like this, most people have no idea what they mean. So what you want to remember is that the trick to adjusting the brightness is using white paper like copy paper. Compare the paper under the lighting in the room to the screen, and adjust the brightness of the display so that the brightness matches as closely as possible. This will put the brightness at about the right level.

Particularly, when using the display for work, you’ll often be comparing paper documents with documents on the screen, so by adjusting the brightness of the screen to the brightness of the paper under the lighting, you’ll reduce the strain on your eyes, making this an effective measure against eye fatigue.

What you need to remember is that if the brightness of the room where the display is installed changes dramatically in the morning, afternoon and evening, the brightness of the screen needs to be changed accordingly, or there’s no point. If you have to adjust it frequently like that, doing it manually is bothersome, and keeping it up becomes difficult. Consider purchasing a display that comes with a function to automatically adjust screen brightness to the optimal setting according to external light.

KWin tiling window scripts

Bismuth and Kröhnkite are Kwin scripts that tiles windows automatically and lets you manage them via keyboard. Bismuth is more actively developed.

Theme details

Themes are stored in:

  • System/Default: /usr/share/plasma/desktoptheme/
  • User Installed: ~/.local/share/plasma/desktoptheme/

Backup KDE settings

One thing to be aware of if you ever need to restore it. When you log out your session, Plasma writes its current state to the file as it closes down. So you can’t replace the file with your backup while you’re in a Plasma session. You need to log out, then either log in with a different desktop or (my method) open a new TTY (<ctrl><alt><f2>), log in there and replace the file. Then go back to your primary tty (probably <ctrl><alt><f1>) and log in . Voila! your desktop will be restored

PlasmaConfSaver

+ /.config/

# plasma
+ /.config/plasma-org.kde.plasma.desktop-appletsrc
+ /.config/plasmarc
+ /.config/plasmashellrc
+ /.config/kdeglobals

# kwin
+ /.config/kwinrc
+ /.config/kwinrulesrc

# dolphin
+ /.config/dolphinrc

# desktop session
+ /.config/ksmserverrc

# input devices
+ /.config/kcminputrc

# shortcuts
+ /.config/kglobalshortcutsrc

# klipper
+ /.config/klipperrc

# konsole
+ /.config/konsolerc

# kscreenlocker
+ /.config/kscreenlockerrc

# krunner
+ /.config/krunnerrc

# fonts
+ /.config/kcmfonts

plasma5-wallpapers-dynamic

这个是支持 MacOS 那种 Solar Dynamic Wallpaper 的。可以通过 opi 安装或在 obs 找到安装包

$ opi plasma5-wallpapers-dynamic

使用 MacOS 的 HEIC 格式的动态壁纸:

$ curl -sLO https://raw.githubusercontent.com/zzag/plasma5-wallpapers-dynamic-extras/master/dynamicwallpaperconverter
$ chmod +x dynamicwallpaperconverter
$ sudo zypper in heif-examples
$ ./dynamicwallpaperconverter --crossfade file.heic

Konversation

openSUSE 的 Konversation 用 Libera.Chat 做服务器,如果你的 IP 段被 libera chat 官方限制为必须 SASL 的了,可挂代理用 libera chat 网页版注册 nickname 后再用 konversation 登录

但在实际使用时,经常报错导致无法使用:

Error during SSL handshake: error:1408F10B:SSL routines:ssl3_get_record:wrong version number.

从 ircs://irc.opensuse.org:8001 切换至 ircs://irc.libera.chat:6697 后,就可以正常使用了。

System Tools

Zypper

Zypper 是用于安装、更新和去除包的命令行包管理器。它还可管理储存库。这一点对于完成远程软件管理任务或从外壳脚本管理软件尤其有用。

一般使用

Zypper 的常用语法为:

zypper [--global-options] COMMAND  [--command-options] [arguments]

有关常规选项和所有命令的列表,请参见 zypper help。要获取有关特定命令的帮助,请键入 zypper help 命令

  • Zypper 命令

    执行 Zypper 最简单的方式是,键入其名称后跟一个命令。例如,要将所有需要的增补程序应用于系统,请使用:

    $ sudo zypper patch
    
  • 全局选项

    此外,您还可以选择使用一个或多个全局选项,只需在命令前面键入它们即可:

    $ sudo zypper --non-interactive patch
    

    在上面的示例中,选项 --non-interactive 表示在不询问任何问题的情况下运行命令(自动应用默认回答)。

  • 命令特定的选项

    要使用特定于某个命令的选项,请紧接在该命令后面键入这些选项:

    $ sudo zypper patch --auto-agree-with-licenses
    

    在上面的示例中,--auto-agree-with-licenses 用于将所有需要的增补程序应用于系统,不要求您确认任何许可条款,而是自动接受许可条款。

  • 自变量

    某些命令需要一个或多个自变量。例如,使用 install 命令时,需要指定您要安装的一个或多个包:

    $ sudo zypper install mplayer
    

    某些选项还需要单个自变量。用以下命令可列出所有已知模式:

    $ zypper search -t pattern
    

您可以组合上述所有模式。例如,下面的命令在冗长模式下运行时将安装 mc and vim 包(来自 factory 储存库):

$ sudo zypper -v install --from factory mc vim

--from 选项确保了在从指定储存库请求包时保留所有储存库的启用状态(用于解析任何依赖项)。

多数 Zypper 命令都有 dry-run 选项,它模拟给定的命令。它可用于测试。

$ sudo zypper remove --dry-run MozillaFirefox

Zypper 支持 --userdata 字符串全局选项。您可以使用此选项指定一个将会写入 Zypper 的日志文件和插件(例如 Btrfs 插件)的字符串。它可以用于标记和标识日志文件中的事务。

$ sudo zypper --userdata STRING patch

使用 Zypper 安装和删除软件

要安装或去除包,请使用以下命令:

$ sudo zypper install PACKAGE_NAME$ sudo zypper remove PACKAGE_NAME

警告:不要去除必需的系统包,例如 glibc 、zypper、kernel。如果去除这些包,系统可能会变得不稳定,或完全停止工作。

选择要安装或去除的包

可以使用 zypper installzypper remove 命令通过多种方法来找到包。

  • 按确切的包名称

    $ sudo zypper install MozillaFirefox
    
  • 按确切的包名称和版本号

    $ sudo zypper install MozillaFirefox-52.2
    
  • 按储存库别名和包名称

    $ sudo zypper install mozilla:MozillaFirefox
    

    其中 mozilla 是用于安装的储存库别名。

  • 使用通配符按包名称

    您可以选择名称以特定字符串开头或结尾的所有包。使用通配符要小心,特别是去除包的时候。以下命令将安装名称以“Moz”开头的所有包:

    $ sudo zypper install 'Moz*'
    

    提示:在调试问题时,您有时需要临时安装大量的 -debuginfo 包,以获取有关正在运行的进程的详细信息。在调试会话完成后,如果您需要清理环境,请运行以下命令:

    $ sudo zypper remove '*-debuginfo'
    
  • 按功能

    例如,要安装不知道名称的包,这些功能就很有用。下面的命令将安装包 MozillaFirefox:

    $ sudo zypper install firefox
    
  • 按功能、硬件体系结构或版本

    • 所需硬件体系结构的名称需要追加在功能的后面,两者以句点分隔。例如,要指定 AMD64/Intel 64 体系结构(在 Zypper 中命名为 x86_64),请使用:

      $ sudo zypper install 'firefox.x86_64'
      
    • 版本必须追加到字符串的末尾,并且前面必须带有一个运算符:<(小于)、<=(小于等于)、=(等于)、>=(大于等于)或 >(大于)。

      $ sudo zypper install 'firefox>=52.2'
      
    • 还可以指定硬件体系结构与版本组合要求:

      $ sudo zypper install 'firefox.x86_64>=52.2'
      
  • 按 RPM 文件的路径

    您还可以指定包的本地或远程路径:

    $ sudo zypper install /tmp/install/MozillaFirefox.rpm$ sudo zypper install http://download.example.com/MozillaFirefox.rpm
    
同时安装和去除包

要同时安装和去除包,请使用 +/- 修饰符。要安装 emacs 并同时去除 vim ,请使用:

$ sudo zypper install emacs -vim

要去除 emacs 并同时安装 vim ,请使用:

$ sudo zypper remove emacs +vim

为避免 - 开头的包名称被解释为命令行选项,要始终把它用作第二个自变量。如果做不到这点,在它之前加上 --

$ sudo zypper install -emacs +vim       # Wrong$ sudo zypper install vim -emacs        # Correct$ sudo zypper install -- -emacs +vim    # Correct$ sudo zypper remove emacs +vim         # Correct
清理已去除包的依赖项

如果您想将在指定的包去除后不再需要的所有包(随指定的包)自动去除,请使用 --clean-deps 选项:

$ sudo zypper rm PACKAGE_NAME --clean-deps
在脚本中使用 Zypper

默认情况下,在安装或删除选定包之前发生问题时,Zypper 会要求确认。您可以使用 --non-interactive 选项覆盖此行为。必须在实际命令(installremovepatch)的前面指定此选项,如下所示:

$ sudo zypper --non-interactive install PACKAGE_NAME

该选项允许在脚本和 cron 任务中使用 Zypper。

安装或下载源包

要安装某个包的对应源代码包,请使用:

$ zypper source-install PACKAGE_NAME

root 身份执行时,源包的默认安装位置为 /usr/src/packages/;以用户身份运行时,则为 ~/rpmbuild。可以在本地 rpm 配置中更改这些值。

使用此命令还会安装指定包的版本依赖项。如果不想执行此操作,请添加开关 -D

$ sudo zypper source-install -D PACKAGE_NAME

要只安装版本依赖项,请使用 -d

$ sudo zypper source-install -d PACKAGE_NAME

当然,只有当储存库列表中启用了含有源包的储存库时,才能这样做(默认添加但不启用它)。

可使用以下方法来获取储存库中所有源包的列表:

$ zypper search -t srcpackage

您也可以将所有已安装软件包的源包下载到本地目录。要下载源包,请使用:

$ zypper source-download

默认的下载目录是 /var/cache/zypper/source-download。您可以使用 --directory 选项更改下载目录。若只想显示缺失或多余的包而不进行下载或删除任何内容,请使用 --status 选项。要删除多余的源包,请使用 --delete 选项。要禁用删除,请使用 --no-delete 选项。

从禁用的储存库安装包

通常,您只能安装或刷新来自启用的储存库的包。--plus-content 标记选项可帮助您指定要刷新的、要在当前 Zypper 会话期间暂时启用的,以及要在会话完成后禁用的储存库。

例如,要启用可以提供其他 -debuginfo-debugsource 包的储存库,请使用 --plus-content debug。可以多次指定此选项。

要暂时启用此类“调试”储存库以安装特定的 -debuginfo 包,请按如下所示使用该选项:

$ sudo zypper --plus-content debug \   install "debuginfo(build-id)=eb844a5c20c70a59fc693cd1061f851fb7d046f4"

对于缺少的 debuginfo 包,gdb 将会报告 build-id 字符串。

实用程序

要校验所有依赖项是否仍然满足,并修复缺少的依赖项,请使用:

$ zypper verify

除了依赖项必须满足外,某些包还“推荐”其他包。只有在实际可用并可安装时才会安装这些推荐包。如果推荐的包在推荐它们的包已安装(通过添加其他包或硬件)之后才可用,请使用以下命令:

$ sudo zypper install-new-recommends

此命令在插入网络摄像头或 Wi-Fi 设备后非常有用。如果可用,它将安装设备驱动程序和相关软件。只有在满足特定硬件依赖项后,才可安装驱动程序和相关软件。

使用 Zypper 更新软件

用 Zypper 更新软件有三种方式:安装包、安装包的新版本或更新整个分发包。最后一种方式可通过 zypper dist-upgrade 来实现。

安装全部所需的增补程序

要安装所有适用于您系统的正式发布的增补程序,请运行:

$ sudo zypper patch

系统将会检查您计算机上配置的储存库中提供的所有增补程序是否与您的安装相关。如果相关(未分为可选功能类别),则会立即安装这些增补程序。

如果即将安装的增补程序所包含的更改要求重引导系统,您会在重引导前收到警告。

单纯使用 zypper patch 命令不会应用来自第三方储存库的包。要同时更新第三方储存库,请使用 with-update 命令选项,如下所示:

$ sudo zypper patch --with update

要额外安装可选增补程序,请使用:

$ sudo zypper patch --with-optional

要安装与特定 Bugzilla 问题相关的所有增补程序,请使用:

$ sudo zypper patch --bugzilla=NUMBER

要安装与特定 CVE 数据库项相关的所有增补程序,请使用:

$ sudo zypper patch --cve=NUMBER

例如,要安装 CVE 编号为 CVE-2010-2713 的安全增补程序,请执行:

$ sudo zypper patch --cve=CVE-2010-2713

如果只想安装影响 Zypper 和包管理本身的增补程序,请使用:

$ sudo zypper patch --updatestack-only

请记住,如果您使用了 updatestack-only 命令选项,将会丢弃原本还会更新其他储存库的其他命令选项。

列出增补程序

为了让您确定增补程序是否可用,Zypper 允许您查看以下信息:

  • 所需增补程序的数目

    要列出所需增补程序(适用于您的系统但尚未安装的增补程序)的数目,请使用 patch-check

    $ zypper patch-checkLoading repository data...Reading installed packages...5 patches needed (1 security patch)
    

    可以结合 --updatestack-only 选项使用此命令,以便仅列出影响 Zypper 和包管理本身的增补程序。

  • 所需增补程序的列表

    要列出全部所需的增补程序(适用于您的系统但尚未安装的增补程序),请使用 list-patches

    $ zypper list-patchesLoading repository data...Reading installed packages...Repository     | Name        | Version | Category | Status  | Summary---------------+-------------+---------+----------+---------+---------SLES12-Updates | SUSE-2014-8 | 1       | security | needed  | openssl: Update for OpenSSL
    
  • 所有增补程序的列表

    要列出可用的所有增补程序,而不管它们是否已安装或适用于您的安装,请使用 zypper patches

    还可以列出并安装与特定问题相关的增补程序。要列出特定的增补程序,请使用带以下选项的 zypper list-patches 命令:

    • 按 Bugzilla 问题

      要列出与 Bugzilla 问题相关的全部所需增补程序,请使用 --bugzilla 选项。

      要列出针对特定 Bug 的增补程序,您也可以指定 Bug 编号:--bugzilla=编号。要搜索与多个 Bugzilla 问题相关的增补程序,请在 bug 编号之间添加逗号,例如:

      $ zypper list-patches --bugzilla=972197,956917
      
    • 按 CVE 编号

      要列出与 CVE(公共漏洞和披露)数据库中某个项相关的全部所需增补程序,请使用 --cve 选项。

      要列出针对特定 CVE 数据库项的增补程序,您也可以指定 CVE 编号:--cve=*编号*。要搜索与多个 CVE 数据库项相关的增补程序,请在 CVE 编号之间添加逗号,例如:

      $ zypper list-patches --bugzilla=CVE-2016-2315,CVE-2016-2324
      

要列出所有增补程序而不管是否需要安装它们,请另外使用 --all 选项。例如,要列出指派有 CVE 编号的所有增补程序,请使用:

$ zypper list-patches --all --cveIssue | No.           | Patch             | Category    | Severity  | Status------+---------------+-------------------+-------------+-----------+----------cve   | CVE-2015-0287 | SUSE-SLE-Module.. | recommended | moderate  | neededcve   | CVE-2014-3566 | SUSE-SLE-SERVER.. | recommended | moderate  | not needed[...]
安装新的包版本

如果某个安装源只包含新包,但未提供增补程序,则 zypper patch 不会产生任何作用。要使用可用的较新版本更新所有已安装的包(同时还要保持系统完整性),请使用︰

$ sudo zypper update

要更新个别包,请用更新或安装命令指定包:

$ sudo zypper update PACKAGE_NAME$ sudo zypper install PACKAGE_NAME

可使用此命令来获取所有新的可安装包的列表:

$ zypper list-updates

请注意,此命令只会列出符合以下准则的包︰

  • 与已安装的包拥有相同的供应商,
  • 由至少与已安装包拥有相同优先级的储存库提供,
  • 可安装(满足所有依赖项)。

所有新的可用包(无论是否可安装)的列表可通过以下方式获取:

$ sudo zypper list-updates --all

要找出新包无法安装的原因,请使用上面所述的 zypper installzypper update 命令。

识别孤立的包

每当您从 Zypper 中去除某个储存库或者升级系统时,某些包可能会进入“孤立”状态。这些孤立的包不再属于任何活动储存库。以下命令可以列出这些包:

$ sudo zypper packages --orphaned

借助此列表,您可以确定是否仍然需要某个包,或者是否可以安全去除某个包。

识别使用已删除文件的进程和服务

在增补、更新或去除包时,系统上可能有一些正在运行的进程会继续使用更新或去除后已被删除的文件。运行 zypper ps 可以列出使用已删除文件的进程。如果此类进程属于某个已知的服务,则会列出服务名称,方便您重启动该服务。默认情况下,zypper ps 会显示一个表:

PID   | PPID | UID | User  | Command      | Service      | Files------+------+-----+-------+--------------+--------------+-------------------814   | 1    | 481 | avahi | avahi-daemon | avahi-daemon | /lib64/ld-2.19.s->      |      |     |       |              |              | /lib64/libdl-2.1->      |      |     |       |              |              | /lib64/libpthrea->      |      |     |       |              |              | /lib64/libc-2.19->[...]
  • PID:进程的 ID
  • PPID:父进程的 ID
  • UID:运行进程的用户的 ID
  • User:运行进程的用户的登录名
  • Command:用于执行进程的命令
  • Service:服务名称(仅当命令与系统服务关联时才显示)
  • Files:已删除文件的列表

通过如下方式可控制 zypper ps 的输出格式:

  • zypper ps -s

    创建一份简短表格,其中不会显示已删除的文件。

    PID   | PPID | UID  | User    | Command      | Service------+------+------+---------+--------------+--------------814   | 1    | 481  | avahi   | avahi-daemon | avahi-daemon817   | 1    | 0    | root    | irqbalance   | irqbalance1567  | 1    | 0    | root    | sshd         | sshd1761  | 1    | 0    | root    | master       | postfix1764  | 1761 | 51   | postfix | pickup       | postfix1765  | 1761 | 51   | postfix | qmgr         | postfix2031  | 2027 | 1000 | tux     | bash         |
    
  • zypper ps -ss

    仅显示与系统服务关联的进程。

    PID   | PPID | UID  | User    | Command      | Service------+------+------+---------+--------------+--------------814   | 1    | 481  | avahi   | avahi-daemon | avahi-daemon817   | 1    | 0    | root    | irqbalance   | irqbalance1567  | 1    | 0    | root    | sshd         | sshd1761  | 1    | 0    | root    | master       | postfix1764  | 1761 | 51   | postfix | pickup       | postfix1765  | 1761 | 51   | postfix | qmgr         | postfix
    
  • zypper ps -sss

    仅显示使用已删除文件的系统服务。

    avahi-daemonirqbalancepostfixsshd
    
  • zypper ps --print "systemctl status %s"

    显示用于检索可能需要重启动的服务状态信息的命令。

    systemctl status avahi-daemonsystemctl status irqbalancesystemctl status postfixsystemctl status sshd
    

用 Zypper 管理安装源

Zypper 的所有安装或增补程序命令均基于已知安装源列表。要列出系统已知的所有储存库,请使用命令:

$ zypper repos

结果将类似于与以下输出:

# | Alias        | Name          | Enabled | Refresh--+--------------+---------------+---------+--------1 | SLEHA-12-GEO | SLEHA-12-GEO  | Yes     | No2 | SLEHA-12     | SLEHA-12      | Yes     | No3 | SLES12       | SLES12        | Yes     | No

当在各个命令中指定储存库时,可以使用别名、URI 或 zypper repos 命令输出中的储存库编号。储存库别名是用于储存库处理命令中的储存库名称的简短版本。请注意,在修改储存库列表后,储存库编号可能会更改。别名本身不会更改。

默认情况下不显示储存库的 URI 或优先级之类的细节。用以下命令可以列出所有细节:

$ zypper repos -d

添加安装源

要添加安装源,请运行

$ sudo zypper addrepo URI ALIAS

URI 可以是因特网储存库、网络资源、目录、CD 或 DVD。ALIAS 是储存库的唯一简写标识符。您可以随意选择别名,前提是它必须唯一。如果指定的别名已在使用,Zypper 将发出警告。

刷新储存库

zypper 可让您从配置的储存库中提取包的更改。要提取更改,请运行:

$ sudo zypper refresh

注意:有些命令默认会自动执行 refresh,因此您不需要明确运行该命令。

使用 refresh 命令时搭配 --plus-content 选项还可查看已禁用储存库中的更改:

$ sudo zypper --plus-content refresh

该选项虽然会提取储存库中的更改,但会使禁用储存库的状态保持不变,即仍为禁用。

删除储存库

要从列表中去除某个储存库,请将命令 zypper removerepo 与要删除的储存库的别名或编号结合使用。例如

$ sudo zypper removerepo 1$ sudo zypper removerepo "SLEHA-12-GEO"
修改储存库

zypper modifyrepo 启用或禁用储存库。您还可以用该命令更改储存库的属性(例如刷新行为、名称或优先级)。以下命令将会启用名为 updates 的储存库、打开自动刷新并将其优先级设置为 20:

$ sudo zypper modifyrepo -er -p 20 'updates'

修改储存库并不局限于单个储存库 —— 您也可以对组执行该操作︰

  • -a:所有储存库
  • -l:本地储存库
  • -t:远程储存库
  • -m 类型:特定类型的储存库(其中类型可以是以下之一:http、https、ftp、cd、dvd、dir、file、cifs、smb、nfs、hd 和 iso)

要重命名安装源别名,请使用 renamerepo 命令。以下示例将别名从 Mozilla Firefox 更改为 firefox

$ sudo zypper renamerepo 'Mozilla Firefox' firefox

用 Zypper 查询储存库和包

Zypper 提供各种查询储存库或包的方式。要获取所有可用的产品、模式、包或增补程序的列表,请使用以下命令:

$ zypper products$ zypper patterns$ zypper packages$ zypper patches

要查询特定包的所有储存库,请使用 search。要获得有关特定包的信息,请使用 info 命令。

搜索软件

zypper search 命令可对包名或(视情况)对包摘要和说明执行搜索。括在 / 中的字符串会解译为正则表达式。默认情况下搜索不区分大小写。

  • 执行简单搜索来查找包含 fire 的包名称

    $ zypper search "fire"
    
  • 执行简单搜索来查找确切的包 MozillaFirefox

    $ zypper search --match-exact "MozillaFirefox"
    
  • 同时在包描述和摘要中搜索

    $ zypper search -d fire
    
  • 仅显示尚未安装的包

    $ zypper search -u fire
    
  • 显示包含字符串 fir 且该字符串后面不是 e 的包

    $ zypper se "/fir[^e]/"
    
搜索特定功能

要搜索提供特殊功能的包,请使用命令 what-provides。例如,如果您想知道哪个包提供 Perl 模块 SVN::Core,请使用以下命令:

$ zypper what-provides 'perl(SVN::Core)'

what-provides 包名rpm -q --whatprovides 包名 类似,不过 RPM 只能查询 RPM 数据库(即所有已安装的包的数据库)。另一方面,Zypper 将告诉您任意储存库的功能的提供商,而非仅已安装的储存库功能的提供商。

显示包信息

要查询个别包,请使用 info 命令,并用完整包名称作为自变量。这会显示有关某个包的详细信息。如果包名与储存库中的所有包名都不匹配,该命令会输出非包匹配项的详细信息。如果您请求特定类型(通过使用 -t 选项),但该类型不存在,该命令会输出其他可用的匹配项,但不提供详细信息。

如果您指定源包,该命令会显示基于该源包构建的二进制包。如果您指定二进制包,该命令会输出用来构建该二进制包的源包。

如果还要显示该包必需/推荐的包,则使用选项 --requires--recommends

zypper info --requires MozillaFirefox

显示生命周期信息

要检查您的产品和所支持包的生命周期,请如下所示使用 zypper lifecycle 命令:

$ zypper lifecycleProduct end of supportCodestream: SUSE Linux Enterprise Server 15             2028-04-23    SUSE Linux Enterprise Server 15                     n/a*Module end of supportBasesystem Module                                       2021-07-31No packages with end of support different from product.*) See https://www.suse.com/lifecycle for latest information

配置 Zypper

Zypper 现在随附配置文件,允许您永久更改 Zypper 的行为(系统范围或用户特定)。要进行系统范围更改,请编辑 /etc/zypp/zypper.conf。要进行用户特定的更改,请编辑 ~/.zypper.conf。如果 ~/.zypper.conf 尚不存在,您可以使用 /etc/zypp/zypper.conf 作为模板:将其复制到 ~/.zypper.conf 并根据您的喜好进行调整。请参见文件中的注释,获取有关可用选项的帮助。

查错

如果您在访问配置的储存库中的包时遇到问题(例如,尽管您知道某个包在某个储存库中,但 Zypper 找不到该包),刷新储存库或许可以解决问题:

sudo zypper refresh

如果不起作用,则尝试

sudo zypper refresh -fdb

这会强制完全刷新和重构建数据库,包括强制下载原始元数据。

Btrfs 文件系统上的 Zypper 回滚功能

如果根分区上使用的是 Btrfs 文件系统,且系统中安装了 snapper,当 Zypper 提交对文件系统所做的更改以创建相应的文件系统快照时,会自动调用 snapper。这些快照可用于还原 Zypper 进行的任何更改。

zypper autoremove

zypper 提供了 subcommand 子命令的功能,可以将自定义脚本当作 zypper 命令来执行。所以可以编写这样一个脚本:

$ sudo vi /usr/lib/zypper/commands/zypper-autoremove
#!/bin/sh
packages=$(zypper packages --unneeded | awk -F'|' 'NR==0 || NR==1 || NR==2 || NR==3 || NR==4 {next} {print $3}')
if [[ -n "$packages" ]]; then
    echo $packages | xargs zypper remove --clean-deps
else
    echo "No unneeded package found."
fi

$ sudo chmod u+x /usr/lib/zypper/commands/zypper-autoremove
  • zypper pa --unneeded 列出当前已被自动安装但未被其他包依赖的无用软件包

命名为 zypper-autoremove,放在你的 $PATH 下或者 /usr/lib/zypper/commands 里面,就可以通过如下命令来实现清理无用包的功能了:

$ sudo zypper autoremove

相关讨论:

zypper auto-refreshes

Zypper auto-refreshes the repos when you run it. Disable it.

$ sudo zypper mr -aR

-R is legacy. -F should also work. If no name is specified, the action is done on all repos.

Firewall-cmd

Firewall-cmd 是 Firewalld 的命令行工具。

firewall-cmd(firewalld command line client) 是 firewalld 的主要命令行工具。它可以用来获取 firewalld 的状态信息,获取运行时和永久环境的防火墙配置,也可以用来修改这些配置。根据所选择的策略,你需要通过 Root 认证才能访问或更改 firewalld 的配置。它只有在 firewalld 运行的情况下才能使用。firewall-cmd 充当 nftables/iptables 的前端。

该文主要描述 firewall-cmd 的简易使用方法,更多内容详见:Firewalld Documentation

准备工作

openSUSE 已经默认安装并激活了 firewalld ,但你可以使用下列方法安装 firewalld :

$ sudo zypper ref
$ sudo zypper update
$ sudo zypper install firewalld

Firewalld 的基本概念

区域(zone)

firewalld 将所有的网络数据流量划分为多个区域,再根据数据包的源IP地址或传入网络接口等条件,将数据流量转入相应区域的防火墙规则中。

你可以通过运行以下 ls 命令查看所有的区域:

$ ls -l /usr/lib/firewalld/zones/

使用 cat 指令查阅某个区域的详细内容

$ cat /usr/lib/firewalld/zones/*.xml

* 的可以替换成:

  1. block:拒绝所有传入的网络连接。只有从系统内部发起的网络连接才可能有效;
  2. dmz:隔离区域也称为非军事化区域 (Demilitarized zone) ,为您的局域网提供有限的访问权限,并且只允许选定的传入端口;
  3. drop:终止所有传入链接,只允许传出的链接;
  4. external:对路由器类型的连接很有用。你需要局域网和广域网的接口来进行伪装(NAT)才能正常工作。
  5. home:适用于家庭电脑,如局域网内的笔记本电脑和台式机,您可以信任其他电脑。只允许选定的 TCP/IP 端口;
  6. internal:用于内部网络,当你几乎信任局域网内的其他服务器或计算机时;
  7. public(系统默认值):适用于始终处于公共区域的云服务器或托管在您处的服务器。您不信任网络上的任何其他计算机和服务器。您只允许使用所需的端口和服务;
  8. trusted:允许任何的网络链接;
  9. work:适用于您信任您的同事和其他服务器的工作场所。

查看所有区域:

$ sudo firewall-cmd --get-zones

查看默认区域:

$ sudo firewall-cmd --get-default-zone  #### OR
$ sudo grep -i DefaultZone /etc/firewalld/firewalld.conf

openSUSE 默认的区域是 public ,默认启用的服务是 ssh 和 dhcpv6-client 。 查看网络接口名称:

$ ip link show

当 NetworkManager 添加新的接口连接(如 eth0 或 ens3)时,它们将被连接到默认的区域。通过运行以下命令进行验证:

$ firewall-cmd --get-active-zones
服务(services)

服务是一个包含了本地端口、协议、源端口、目的地和防火墙帮助模块 (firewall helper modules) 的列表,在 /usr/lib/firewalld/services/ 目录。

查询与 public 相关的防火墙规则或服务:

$ sudo firewall-cmd --list-all --zone=public
public (active)
  target: default
  icmp-block-inversion: no
  interfaces: wlan0
  sources: 
  services: dhcpv6-client
  ports: 
  protocols: 
  masquerade: no
  forward-ports: 
  source-ports: 
  icmp-blocks: 
  rich rules:

在该查询结果中,默认区域是 public ,允许的服务是 dhcpv6-client 。假设你需要删除 dhcpv6-client ,那么你应该运行如下指令:

$ sudo firewall-cmd --remove-service=dhcpv6-client --permanent --zone=public
$ sudo firewall-cmd --reload #### 重载防火墙
$ sudo firewall-cmd --list-services #### 列出所有服务

运行下列指令查询特定区域允许的服务列表:

$ sudo firewall-cmd --list-services #### 查询当前区域允许的服务
$ sudo firewall-cmd --list-services --zone=* #### 将 * 替换成你所需要查询服务的区域
$ sudo firewall-cmd --list-all-zones #### 查询全部区域的服务或防火墙规则

启动、检查和关闭 firewalld 服务

启动(Start)并激活(Enable)防火墙:

$ sudo systemctl start firewalld
$ sudo systemctl enable firewalld

检查防火墙服务状态:

$ sudo systemctl status firewalld

检查防火墙状态:

$ sudo firewall-cmd --state

检查 firewalld 是否开机启动:

$ sudo systemctl is-enabled firewalld

更改规则后,重启防火墙让规则生效:

$ sudo firewall-cmd --reload

暂停(Stop)和关闭(Disable)防火墙:

$ sudo systemctl stop firewalld
$ sudo systemctl disable firewalld

运行时和永久规则

运行时的 firewalld 配置更改是临时性的,当你重新启动 openSUSE 或 firewalld 时,它们就会消失。永久规则则不受影响。 例如

$  sudo firewall-cmd --zone=public --add-service=kdeconnect #### 运行时规则
$  sudo firewall-cmd --zone=public --add-service=kdeconnect --permanent #### 永久规则

添加永久性规则

$ sudo firewall-cmd --zone=* --add-service=** --permanent #### 将 * 替换成区域,将 ** 替换成服务名称,如 https.
$ sudo firewall-cmd --reload #### 重启防火墙让规则生效。

确认规则是否生效:

$ sudo firewall-cmd --list-services
$ sudo firewall-cmd --list-services --permanent

查询 firewalld 支持的服务列表

$ sudo firewall-cmd --get-services
$ sudo firewall-cmd --get-services | grep kdeconnect
$ ls -l /usr/lib/firewalld/services/
$ cat /usr/lib/firewalld/services/kdeconnect.xml

Firewall-cmd 规则集样例

添加 DNS 服务(TCP/UDP 端口:53,区域为 public,永久性规则):

$ sudo firewall-cmd --zone=public --add-service=dns --permanent

删除某个服务(例如 VNC 服务器服务,TCP 端口:5900-5903,区域为 public,永久性规则):

$ sudo firewall-cmd --zone=public --remove-service=vnc-server --permanent

开放特定的端口(TCP/UDP),例如开放 TCP/UDP 端口:55527:

$ sudo firewall-cmd --zone=public --add-port=55527/tcp --permanent
$ sudo firewall-cmd --zone=public --add-port=55527/udp --permanent

查看已开放的端口:

$ sudo firewall-cmd --zone=public --list-ports
$ sudo firewall-cmd --zone=public --list-ports --permanent

拒绝/禁用特定端口:

$ sudo firewall-cmd --zone=public --remove-port=23/tcp --permanent

注意,当 firewalld 的区域是 public 的时候,绝大多数端口是默认禁用的。

编写端口转发 Firewalld 规则

将同一服务器上的 TCP 端口 443 转发到 8080:

$ sudo firewall-cmd --zone=public --add-forward-port=port=80:proto=tcp:toport=8080 --permanent

要删除上述端口转发,请运行下列指令:

$ sudo firewall-cmd --zone=public --remove-forward-port=port=80:proto=tcp:toport=8080

如果您需要将流量 (端口 443) 转发到 192.168.2.42 端口 443 的 lxd 服务器/容器,请开启伪装功能:

$ sudo firewall-cmd --zone=public --add-masquerade
$ sudo firewall-cmd --zone=public --add-forward-port=port=443:proto=tcp:toport=443:toaddr=192.168.2.42 --permanent

要删除上述伪装规则,请运行下列指令:

$ sudo firewall-cmd --zone=public --remove-masquerade
$ sudo firewall-cmd --zone=public --remove-forward-port=port=443:proto=tcp:toport=443:toaddr=192.168.2.42 --permanent

列出规则:

$ sudo firewall-cmd --zone=public --list-all --permanent

Rich rule 示例

假设你想只允许从 192.168.0.0 子网的 IP 地址访问 KDE Connect 的端口,运行下列指令:

$ sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.2.0/24" port protocol="tcp" port="1714-1764" accept'
$ sudo firewall-cmd --permanent --zone=public --add-rich-rule='rule family="ipv4" source address="192.168.2.0/24" port protocol="udp" port="1714-1764" accept'

要验证新规则,请运行下列指令:

$ sudo firewall-cmd --list-rich-rules --permanent

您可以通过以下方式删除富规则:

$ sudo firewall-cmd --permanent --zone=public --remove-rich-rule 'rule family="ipv4" source address="192.168.0.0/24" port protocol="udp" port="1714-1764" accept' 

其他

如果你更青睐于GUI,那么你可以考虑使用Yast自带的防火墙,或者使用 firewall-config:

$ sudo zypper install firewall-config

sudo

许多命令和系统实用程序都需要以 root 身份运行才能执行。为了确保安全和避免发生意外运行危险命令,通常建议不要直接以 root 身份登录。建议的做法是以非特权的普通用户身份工作,并使用 sudo 命令来运行需要较高特权的命令。

在 SUSE Linux Enterprise Server 上,sudo 默认配置与 su 的工作方式类似。但是,sudo 可让用户以高度可配置的方式使用任何其他用户的特权来运行命令。这样,便可为某些用户和组指派具有特定特权的角色。举例来说,可以允许组 users 的成员使用 wilber 的特权运行命令。通过禁止指定任何命令选项,可以进一步限制对命令的权限。虽然 su 始终需要 root 口令才能使用 PAM 进行身份验证,但是您可以将 sudo 配置为使用您自己的身份凭证进行身份验证。这样就不需要共享 root 口令,从而提高了安全性。

sudo 基本用法

虽然 sudo 简单易用,功能却十分强大。

运行单个命令

以普通用户身份登录后,您可以在命令前加上 sudoroot 身份运行任何命令。按照提示输入口令后,如果身份验证成功,您便能以 root 身份运行命令:

# id -un 命令会打印当前用户的登录名
$ id -un
tux

# 在输入过程中不会显示口令,无论是明文还是密文均不显示。 
$ sudo id -un
root's password:
root

# 只有以 sudo 开头的命令才会使用较高的特权运行。如果是不带 sudo 前缀的相同命令,仍会使用当前用户的特权运行。 
$ id -un
tux

# 在限定时间内,您无需再次输入 root 口令。 
$ sudo id -un
root

I/O 重定向的工作方式与您预期的可能不同:

$ sudo echo s > /proc/sysrq-trigger
bash: /proc/sysrq-trigger: Permission denied
$ sudo cat < /proc/1/maps
bash: /proc/1/maps: Permission denied

只有 echo/cat 二进制会使用较高特权运行,重定向则由用户外壳使用用户特权执行。您可以按启动外壳中所述启动外壳,也可以使用 dd 实用程序来启动:

$ echo s | sudo dd of=/proc/sysrq-trigger
$ sudo dd if=/proc/1/maps | cat
启动外壳

必须在每条命令前加上 sudo 可能很繁琐。虽然可以将外壳指定为命令 sudo bash,但还是建议您使用以下其中一种内置机制来启动外壳:

  • sudo -s (<命令>)

    启动 SHELL 环境变量所指定的外壳或目标用户的默认外壳。如果给定了命令,则会将该命令传递给外壳(使用 -c 选项),否则外壳会以交互模式运行。

    $ sudo -s
    root's password:
    $ exit
    
  • sudo -i (<命令>)

  • -s 类似,但是会将外壳启动为登录外壳。也就是说,系统会对外壳的启动文件(.profile 等)进行处理,并会将当前的工作目录设置为目标用户的主目录。

    $ sudo -i
    root's password:
    $ exit
    
环境变量

默认情况下,sudo 不会传播环境变量:

$ ENVVAR=test env | grep ENVVAR
ENVVAR=test
$ ENVVAR=test sudo env | grep ENVVAR
root's password:

$

输出为空即表明在使用 sudo 运行的命令的环境中不存在环境变量 ENVVAR

此行为可通过 env_reset 选项进行更改,请参见下文有用的标志和选项

配置 sudo

sudo 是一个非常灵活的工具,提供各种配置选项。

注意:如果您不小心将自己锁定在 sudo 之外,则可以使用 su -root 口令来获取 root 外壳。要修复该错误,请运行 visudo

编辑配置文件

sudo 的主要策略配置文件为 /etc/sudoers。如果此文件中存在错误,您可能便会无法进入系统,因此强烈建议您使用 visudo 来编辑配置文件。此举可防止同时更改打开的文件,并会在保存修改之前检查语法错误。

您还可以通过设置 EDITOR 环境变量来使用除 vi 以外的编辑器(不论名字如何),例如:

$ sudo EDITOR=/usr/bin/nano visudo

不过,/etc/sudoers 文件本身是由系统包提供的,更新时这些修改可能会取消。因此,建议您将自定义配置放到 /etc/sudoers.d/ 目录下的文件中。该目录下的任何文件都会自动纳入系统中。要在该子目录下创建或编辑文件,请运行:

sudo visudo -f /etc/sudoers.d/NAME

或者,使用其他编辑器(例如 nano):

sudo EDITOR=/usr/bin/nano visudo -f /etc/sudoers.d/NAME

注意:/etc/sudoers 中的 #includedir 命令(用于 /etc/sudoers.d)会忽略以 ~(波浪号)结尾或包含 .(点)的文件。

关于 visudo 命令的详细信息,请运行 man 8 visudo

sudoers 基本配置语法

在 sudoers 配置文件中,有两种类型的选项:字符串和标志。字符串可以包含任何值,而标志则只能在“ON”或“OFF”之间切换。sudoers 配置文件最重要的语法构造为:

# Everything on a line after a # gets ignored, 

Defaults !insults # Disable the insults flag 

Defaults env_keep += "DISPLAY HOME" # Add DISPLAY and HOME to env_keep
tux ALL = NOPASSWD: /usr/bin/frobnicate, PASSWD: /usr/bin/journalctl 
  • #include#includedir 这两个普通命令例外。其后跟数字,用于指定 UID。
  • 去除 ! 可将指定的标志设置为“ON”。

有用的标志和选项

选项名称 说明 示例
targetpw 此标志控制调用用户是需要输入目标用户(例如 root)的口令 (ON) 还是需要输入调用用户的口令 (OFF)。 Defaults targetpw # Turn targetpw flag ON
rootpw 如果设置了该选项,sudo 会提示输入 root 口令,而非目标用户或调用者的口令。默认值为“OFF”。 Defaults !rootpw # Turn rootpw flag OFF
env_reset 如果设置了该选项,sudo 会构造一个仅包含 TERMPATHHOMEMAILSHELLLOGNAMEUSERUSERNAMESUDO_* 集的最小环境。此外,会从调用环境导入 env_keep 中列出的变量。默认值为“ON”。 Defaults env_reset # Turn env_reset flag ON
env_keep env_reset 标志设为“ON”时要保留的环境变量列表。 # Set env_keep to contain EDITOR and PROMPT Defaults env_keep = "EDITOR PROMPT" Defaults env_keep += "JRE_HOME" # Add JRE_HOME Defaults env_keep -= "JRE_HOME" # Remove JRE_HOME
env_delete env_reset 标志设为“OFF”时要去除的环境变量列表。 # Set env_delete to contain EDITOR and PROMPT Defaults env_delete = "EDITOR PROMPT" Defaults env_delete += "JRE_HOME" # Add JRE_HOME Defaults env_delete -= "JRE_HOME" # Remove JRE_HOME

还可以使用 Defaults 令牌为用户、主机和命令集合创建别名。并且,可以仅将选项应用到特定用户集。

关于 /etc/sudoers 配置文件的详细信息,请参见 man 5 sudoers

sudoers 中的规则

sudoers 配置中的规则可能会非常复杂,因此本节仅涉及基本内容。每个规则都遵循基本模式([] 标记的是可选部分):

#Who      Where         As whom      Tag                What
User_List Host_List = [(User_List)] [NOPASSWD:|PASSWD:] Cmnd_List
  • User_List

    一个或多个(用 , 分隔)标识符:用户名、格式为 %GROUPNAME 的组或格式为 #UID 的用户 ID。可以使用 ! 前缀来取反。

  • Host_List

    一个或多个(用 , 分隔)标识符:(完全限定的)主机名或 IP 地址。可以使用 ! 前缀来取反。Host_List 的惯常选项为 ALL

  • NOPASSWD:|PASSWD:

    如果用户在 NOPASSWD: 后面运行的命令与 CMDSPEC 匹配,系统不会提示用户输入口令。

    PASSWD 为默认选项,仅当两个选项位于同一行时才需要指定它:

    tux ALL = PASSWD: /usr/bin/foo, NOPASSWD: /usr/bin/bar
    
  • Cmnd_List

    一个或多个(用 , 分隔)区分符:可执行文件的路径,后跟允许使用的自变量或什么也不跟。

    /usr/bin/foo     # Anything allowed
    /usr/bin/foo bar # Only "/usr/bin/foo bar" allowed
    /usr/bin/foo ""  # No arguments allowed
    

ALL 可以用作 User_ListHost_ListCmnd_List

允许 tux 在无需输入口令的情况下以 root 身份运行所有命令的规则:

tux ALL = NOPASSWD: ALL

允许 tux 运行 systemctl restart apache2 的规则:

tux ALL = /usr/bin/systemctl restart apache2

允许 tux 在不带自变量的情况下以 admin 身份运行 wall 的规则:

tux ALL = (admin) /usr/bin/wall ""

警告:以下类型的构造

ALL ALL = ALL

在没有 Defaults targetpw 的情况下切勿使用,否则任何人都能以 root 身份运行命令。

常见使用情况

尽管默认配置对于简单的设置和桌面环境通常已经够用,但是自定义配置非常有用。

在无需 root 口令的情况下使用 sudo

在具有特殊限制(“用户 X 只能以 root” 身份运行命令 Y)的情况下,无法实现此目的。在其他情况下,还是建议进行某种分隔。按照惯例,组 wheel 的成员能以 root 身份运行所有带有 sudo 的命令。

  1. 将自己添加到 wheel

    如果您自己的用户帐户尚不是 wheel 组的成员,请添加该帐户,具体做法是运行 sudo usermod -a -G wheel 用户名然后注销并再次登录。运行 groups 用户名以确认更改是否成功。

  2. 将使用调用用户的口令进行身份验证的选项设为默认设置。

    使用 visudo 创建文件 /etc/sudoers.d/userpw并添加:

    Defaults !targetpw
    
  3. 选择新默认规则。

    根据是否想要用户重新输入口令,取消对 /etc/sudoers 中特定行的注释,并将默认规则注释掉。

    ## Uncomment to allow members of group wheel to execute any command
    # %wheel ALL=(ALL) ALL
    
    ## Same thing without a password
    # %wheel ALL=(ALL) NOPASSWD: ALL
    
  4. 提高默认规则的限制性

    /etc/sudoers 中允许一切操作的规则注释掉或去除:

    ALL     ALL=(ALL) ALL   # WARNING! Only use this together with 'Defaults targetpw'!
    
  5. 警告:切勿漏掉这一步,否则任何用户都能以 root 身份执行任何命令。

  6. 测试配置

    尝试以 wheel 的成员和非成员身份运行 sudo

    # user tux
    $ groups
    users wheel
    $ sudo id -un
    tux's password:
    root
    
    # use wilber
    $ groups
    users
    $ sudo id -un
    wilber is not in the sudoers file.  This incident will be reported.
    
对 X.Org 应用程序使用 sudo

在使用 sudo 启动图形应用程序时,可能会出现以下错误:

$ sudo xterm
xterm: Xt error: Can't open display: %s
xterm: DISPLAY is not set

YaST 会选择 ncurses 界面而非图形界面。

要在通过 sudo 启动的应用程序中使用 X.Org,需要传播环境变量 DISPLAYXAUTHORITY。要进行此项配置,请创建文件 /etc/sudoers.d/xorg并添加下面一行:

Defaults env_keep += "DISPLAY XAUTHORITY"

如尚未设置 XAUTHORITY 变量,请按如下方式设置:

export XAUTHORITY=~/.Xauthority

现在,X.Org 应用程序便可正常运行:

$ sudo yast2

RPM

RPM(RPM 程序包管理器)用于管理软件包。其主要程命令为 rpmrpmbuild。用户、系统管理员和包构建人员可以查询强大的 RPM 数据库以获得有关已安装软件的详细信息。

rpm 有五种模式:安装、卸装(或更新)软件包、重构建 RPM 数据库、查询 RPM 库或独立 RPM 存档、对包执行完整性检查以及对包签名。rpmbuild 可用于从原始源构建可安装的包。

用特殊的二进制格式对可安装 RPM 存档进行打包。这些存档由要安装的程序文件和某些元信息组成,这些元信息供 rpm 在安装过程中配置软件包使用或者储存在 RPM 数据库中进行存档。RPM 存档通常具有扩展名 .rpm

对于一些包,软件开发所需的组件(库、报头、包含文件等)已纳入独立的包中。只有当您要自己编译软件时才需要这些开发包(例如最新的 GNOME 包)。可以通过扩展名 -devel 确定这些开发包,例如包 alsa-develgimp-devel

校验包真实性

RPM 包具有 GPG 签名。要校验 RPM 包的签名,请使用 rpm --checksig PACKAGE-1.2.3.rpm 命令确定该包是来自 SUSE 还是另一个可信机构。特别建议对来自因特网的更新包使用此命令。

修复操作系统中的问题时,您可能需要将问题临时修复 (PTF) 安装到生产系统中。SUSE 提供的包已使用特殊的 PTF 密钥签名。要手动导入该密钥,请使用以下命令:

sudo rpm --import \/usr/share/doc/packages/suse-build-key/suse_ptf_key.asc

导入该密钥后,您可以在系统上安装 PTF 包。

管理包:安装、更新和卸装

安装 RPM 存档的步骤通常十分简单,执行运行:rpm -i PACKAGE.rpm。使用此命令可以安装包,但前提是满足其依赖关系并且不与其他包冲突。如果出现错误消息,rpm 将请求那些需要安装的包以满足依赖关系要求。在后台,RPM 数据库确保不出现冲突 - 一个特定文件只能属于一个包。通过选择不同的选项,您可以强制 rpm 忽略这些默认设置,但这只供专家用户使用。否则,将影响系统的完整性并可能使系统无法更新。

选项 -U--upgrade 以及 -F--freshen 可用于更新包(例如,rpm -F PACKAGE.rpm)。此命令将删除旧版本的文件并立即安装新文件。两个版本之间的差别是:-U 安装系统中以前不存在的包,而 -F 只更新以前安装的包。更新时,rpm 使用以下策略小心更新配置文件:

  • 如果配置文件未被系统管理员更改,则 rpm 将安装适当文件的新版本。系统管理员无需执行任何操作。
  • 如果配置文件在更新前曾被系统管理员更改,则 rpm 会以扩展名 .rpmorig.rpmsave(备份文件)保存更改的文件,并安装新包中的版本。仅当原先安装的文件和较新的版本不同时,才执行此操作。如果是这种情况,则将备份文件(.rpmorig.rpmsave)与新安装的文件进行比较,并在新文件中再次进行更改。之后,请删除所有 .rpmorig.rpmsave 文件,以免以后的更新出现问题。
  • 如果配置文件已存在并且 .spec 文件中指定了 noreplace 标签,则出现 .rpmnew 文件。

更新后,在使用 .rpmsave.rpmnew 文件进行比较后应将它们删除,从而防止它们阻碍以后的更新。如果 RPM 数据库以前未能识别文件,则将为其指派扩展名 .rpmorig。 否则,将使用 .rpmsave。换句话说,.rpmorig 是从异系统格式更新为 RPM 的结果。而 .rpmsave 是从较早的 RPM 更新为较新的 RPM 的结果。.rpmnew 不提供任何有关系统管理员是否对配置文件进行过任何更改的信息。/var/adm/rpmconfigcheck 中提供这些文件的列表。不覆盖某些配置文件(如 /etc/httpd/httpd.conf)以允许继续进行操作。

-U 开关的作用并完全等同于使用 -e 选项进行卸载以及使用 -i 选项进行安装,它还有其他作用。只要可能,就可以使用 -U

要去除包,请输入 rpm -e PACKAGE。仅当不存在未解决的依赖项问题时,此命令才会删除包。例如,只要有其他程序需要 Tcl/Tk,理论上就不能删除它。即使是在这种情况下,RPM 也会向数据库寻求帮助。如果出于任何原因无法进行此删除操作(即使存在其他依赖项),则最好使用选项 --rebuilddb 重构建 RPM 数据库。

增量 RPM 包

增量 RPM 包包含旧版本和新版本的 RPM 包之间的差别。在旧 RPM 上应用增量 RPM 将得到全新的 RPM。不需要旧 RPM 的副本,因为增量 RPM 也可以与已安装的 RPM 一起工作。增量 RPM 包的大小甚至比增补程序 RPM 小,这有利于通过因特网传送更新包。缺点是,涉及增量 RPM 的更新操作与使用纯粹 RPM 或增补程序 RPM 进行更新的情况相比,占用的 CPU 周期要长得多。

makedeltarpmapplydelta 二进制文件是增量 RPM 套件(包 deltarpm)的一部分,可帮助您创建和应用增量 RPM 包。使用以下命令可以创建名为 new.delta.rpm 的增量 RPM。以下命令假设 old.rpmnew.rpm 是存在的:

sudo makedeltarpm old.rpm new.rpm new.delta.rpm

如果旧包已经安装,则使用 applydeltarpm 可以从文件系统重新构建新的 RPM:

sudo applydeltarpm new.delta.rpm new.rpm

如果不访问文件系统而从旧 RPM 得到它,请使用 -r 选项:

sudo applydeltarpm -r old.rpm new.delta.rpm new.rpm

RPM 查询

-q 选项的 rpm 将启动查询,如此用户便可查看 RPM 存档(通过添加选项 -p)并查询已安装包的 RPM 数据库。可以使用多个开关指定所需信息的类型。

选项 含义
-i 包信息
-l 文件列表
-f FILE 查询包含文件 FILE 的包(必须使用 FILE 指定完整路径)
-s 带有状态信息的文件列表(间接指定 -l
-d 仅列出文档文件(间接指定 -l
-c 仅列出配置文件(间接指定 -l
--dump 带有完整详细信息的文件列表(将用于 -l-c-d
--provides 列出包中可被另一个包通过 --requires 请求的功能
--requires, -R 包需要的功能
--scripts 安装脚本(预安装、后安装、卸载)

例如,命令 rpm -q -i wget 显示

Name        : wgetVersion     : 1.14Release     : 17.1Architecture: x86_64Install Date: Mon 30 Jan 2017 14:01:29 CETGroup       : Productivity/Networking/Web/UtilitiesSize        : 2046483License     : GPL-3.0+Signature   : RSA/SHA256, Thu 08 Dec 2016 07:48:44 CET, Key ID 70af9e8139db7c82Source RPM  : wget-1.14-17.1.src.rpmBuild Date  : Thu 08 Dec 2016 07:48:34 CETBuild Host  : sheep09Relocations : (not relocatable)Packager    : https://www.suse.com/Vendor      : SUSE LLC <https://www.suse.com/>URL         : http://www.gnu.org/software/wget/Summary     : A Tool for Mirroring FTP and HTTP ServersDescription :Wget enables you to retrieve WWW documents or FTP files from a server.This can be done in script files or via the command line.Distribution: SUSE Linux Enterprise 12

只有当您指定带有完整路径的完整文件名时,选项 -f 才起作用。根据需要提供任意多个文件名。例如:

rpm -q -f /bin/rpm /usr/bin/wgetrpm-4.11.2-15.1.x86_64wget-1.14-17.1.x86_64

如果只知道部分文件名,则可以使用外壳脚本。当运行所显示的脚本时,将部分文件名以参数的形式传递给脚本。

#! /bin/shfor i in $(rpm -q -a -l | grep $1); do    echo "\"$i\" is in package:"    rpm -q -f $i    echo ""done

rpm -q --changelog PACKAGE 命令会按日期排序显示有关特定包的详细更改信息列表。

借助已安装的 RPM 数据库,可以进行校验检查。使用 -V--verify 启动这些检查。使用此选项,rpm 显示安装后已被更改的包中的所有文件。rpm 使用 8 个字符符号给出有关以下更改的一些提示:

符号 含义
5 MD5 校验和
S 文件大小
L 符号链接
T 修改时间
D 主要和次要设备编号
U 拥有者
G
M 方式(权限和文件类型)

对于配置文件,将输出字母 c。例如,对于 /etc/wgetrcwget 包)的更改:

rpm -V wgetS.5....T c /etc/wgetrc

RPM 数据库的文件被放置在 /var/lib/rpm 中。如果分区 /usr 的大小为 1 GB,则此数据库可能会占用将近 30 MB,特别是在完全更新之后。如果数据库比预期大得多,则最好使用选项 --rebuilddb 重构建数据库。在执行此操作之前,制作旧数据库的备份。cron 脚本 cron.daily 每天制作数据库的副本(用 gzip 打包)并将这些副本储存在 /var/adm/backup/rpmdb 中。副本的数目是由 /etc/sysconfig/backup 中的变量 MAX_RPMDB_BACKUPS(默认值为 5)控制的。对于 1 GB 的 /usr,单个备份的大小大约为 1 MB。

安装和编译源包

所有源包都带有 .src.rpm 扩展名(源 RPM)。

源包可以从安装媒体复制到硬盘并使用 YaST 解压缩。但是,在包管理器中它们不会被标记为已安装 ([i])。这是因为源包不是在 RPM 数据库中输入的。只有已安装的操作系统软件列在 RPM 数据库中。安装源包时,只将源代码添加到系统中。

以下目录必须可用于 /usr/src/packages 中的 rpmrpmbuild(除非在诸如 /etc/rpmrc 这样的文件中指定自定义设置):

  • SOURCES

    代表原始源(.tar.bz2.tar.gz 文件等)和特定于发布版本的调整(多为 .diff.patch 文件)

  • SPECS

    代表 .spec 文件,类似于元 Makefile,该文件控制构建进程

  • BUILD

    在此目录中解压缩、增补和编译所有源

  • RPMS

    储存完整的二进制包的位置

  • SRPMS

    这里是源 RPM

使用 YaST 安装源包时,将在 /usr/src/packages 中安装所有需要的组件:源和调整在 SOURCES 中,相关的 .spec 文件在 SPECS 中。

警告:不要对系统组件(glibcrpm 等)进行试验,因为这样做会影响系统的稳定性。

下面的示例使用 wget.src.rpm 包。安装源包后,应具有类似以下列表中的文件:

/usr/src/packages/SOURCES/wget-1.11.4.tar.bz2/usr/src/packages/SOURCES/wgetrc.patch/usr/src/packages/SPECS/wget.spec

rpmbuild -bX /usr/src/packages/SPECS/wget.spec 会启动编译。X 是通配符,代表构建进程的不同阶段。以下简要描述:

  • -bp

    /usr/src/packages/BUILD 中准备源:解压和打增补程序。

  • -bc

    执行与 -bp 相同的操作,但还进行编译。

  • -bi

    执行与 -bp 相同的操作,但还安装生成的软件。注意:如果包不支持 BuildRoot 功能,则可能会重写配置文件。

  • -bb

    执行与 -bi 相同的操作,但还创建二进制包。如果编译成功,二进制包应该在 /usr/src/packages/RPMS 中。

  • -ba

    执行与 -bb 相同的操作,但还创建源 RPM。如果编译成功,二进制包应该在 /usr/src/packages/SRPMS 中。

  • --short-circuit

    跳过某些步骤。

现在可以使用 rpm -i 或最好使用 rpm -U 来安装创建的二进制 RPM。使用 rpm 进行安装使它显示在 RPM 数据库中。

使用 build 编译 RPM 包

许多包存在的风险是构建进程中会将许多不需要的文件添加到正在运行的系统中。为防止发生这种情况,请使用 build,它将创建构建包的已定义环境。要建立这一 chroot 环境,build 脚本必须和完整的包树结构一起提供。可以通过 NFS 或从 DVD 使用硬盘上的此树。使用 build --rpms DIRECTORY 设置位置。与 rpm 不同,build 命令在源目录中查找 .spec 文件。要用系统中 /media/dvd 下装入的 DVD 构建 wget(如上例所示),请以 root 用户身份使用以下命令:

cd /usr/src/packages/SOURCES/mv ../SPECS/wget.spec .build --rpms /media/dvd/suse/ wget.spec

随后,将在 /var/tmp/build-root 建立一个最小的环境。在此环境中构建包。完成后,生成的包位于 /var/tmp/build-root/usr/src/packages/RPMS 中。

build 脚本提供多个其他选项。例如,使脚本优先选择您自己的 RPM、忽略构建环境的初始化或者将 rpm 命令限制在上述阶段之一。

用于 RPM 存档和 RPM 数据库的工具

Midnight Commander (mc) 可以显示 RPM 存档的内容并复制部分内容。它将存档表示为虚拟文件系统,提供 Midnight Commander 所有常用的菜单选项。使用 F3 键显示 HEADER。使用光标键和 Enter 键查看存档结构。使用 F5 键复制部分存档。

拥有全部功能的包管理器将作为 YaST 模块提供。

Btrfs

文件系统似乎是内核中比较稳定的部分,多年来,人们一直使用 ext2/3,ext 文件系统以其卓越的稳定性成为了事实上的 Linux 标准文件系统。近年来 ext2/3 暴露出了一些扩展性问题,于是便催生了 ext4 。在 2008 年发布的 Linux2.6.19 内核中集成了 ext4 的 dev 版本。 2.6.28 内核发布时,ext4 结束了开发版,开始接受用户的使用。似乎 ext 就将成为 Linux 文件系统的代名词。然而当您阅读很多有关 ext4 的文章时,会发现都不约而同地提到了 btrfs,并认为 ext4 将是一个过渡的文件系统。 ext4 的作者 Theodore Tso 也盛赞 btrfs 并认为 btrfs 将成为下一代 Linux 标准文件系统。 Oracle,IBM, Intel 等厂商也对 btrfs 表现出了极大的关注,投入了资金和人力。为什么 btrfs 如此受人瞩目呢。这便是本文首先想探讨的问题。

Kevin Bowling 有一篇介绍各种文件系统的文章,在他看来,ext2/3 等文件系统属于“古典时期”。文件系统的新时代是 2005 年由 Sun 公司的 ZFS 开创的。 ZFS 代表” last word in file system ”,意思是此后再也不需要开发其他的文件系统了。 ZFS 的确带来了很多崭新的观念,对文件系统来讲是一个划时代的作品。

如果您比较 btrfs 的特性,将会发现 btrfs 和 ZFS 非常类似。也许我们可以认为 btrfs 就是 Linux 社区对 ZFS 所作出的回应。从此往后在 Linux 中也终于有了一个可以和 ZFS 相媲美的文件系统。

Btrfs 的特性

您可以在 btrfs 的主页上看到 btrfs 的特性列表。我自作主张,将那张列表分成了四大部分。

首先是扩展性 (scalability) 相关的特性,btrfs 最重要的设计目标是应对大型机器对文件系统的扩展性要求。 Extent,B-Tree 和动态 inode 创建等特性保证了 btrfs 在大型机器上仍有卓越的表现,其整体性能而不会随着系统容量的增加而降低。

其次是数据一致性 (data integrity) 相关的特性。系统面临不可预料的硬件故障,Btrfs 采用 COW 事务技术来保证文件系统的一致性。 btrfs 还支持 checksum,避免了 silent corrupt 的出现。而传统文件系统则无法做到这一点。

第三是和多设备管理相关的特性。 Btrfs 支持创建快照 (snapshot),和克隆 (clone) 。 btrfs 还能够方便的管理多个物理设备,使得传统的卷管理软件变得多余。

最后是其他难以归类的特性。这些特性都是比较先进的技术,能够显著提高文件系统的时间 / 空间性能,包括延迟分配,小文件的存储优化,目录索引等。

扩展性相关的特性

B-Tree

btrfs 文件系统中所有的 metadata 都由 BTree 管理。使用 BTree 的主要好处在于查找,插入和删除操作都很高效。可以说 BTree 是 btrfs 的核心。

一味地夸耀 BTree 很好很高效也许并不能让人信服,但假如稍微花费一点儿时间看看 ext2/3 中元数据管理的实现方式,便可以反衬出 BTree 的优点。

妨碍 ext2/3 扩展性的一个问题来自其目录的组织方式。目录是一种特殊的文件,在 ext2/3 中其内容是一张线性表格。

图中展示了一个 ext2 目录文件的内容,该目录中包含四个文件。分别是 “home1”,“usr”,“oldfile” 和 “sbin” 。如果需要在该目录中查找目录 sbin,ext2 将遍历前三项,直至找到 sbin 这个字符串为止。

这种结构在文件个数有限的情况下是比较直观的设计,但随着目录下文件数的增加,查找文件的时间将线性增长。 2003 年,ext3 设计者开发了目录索引技术,解决了这个问题。目录索引使用的数据结构就是 BTree 。如果同一目录下的文件数超过 2K,inode 中的 i_data 域指向一个特殊的 block 。在该 block 中存储着目录索引 BTree 。 BTree 的查找效率高于线性表,

但为同一个元数据设计两种数据结构总是不太优雅。在文件系统中还有很多其他的元数据,用统一的 BTree 管理是非常简单而优美的设计。

Btrfs 内部所有的元数据都采用 BTree 管理,拥有良好的可扩展性。 btrfs 内部不同的元数据由不同的 Tree 管理。在 superblock 中,有指针指向这些 BTree 的根。如图 2 所示:

FS Tree 管理文件相关的元数据,如 inode,dir 等; Chunk tree 管理设备,每一个磁盘设备都在 Chunk Tree 中有一个 item ; Extent Tree 管理磁盘空间分配,btrfs 每分配一段磁盘空间,便将该磁盘空间的信息插入到 Extent tree 。查询 Extent Tree 将得到空闲的磁盘空间信息; Tree of tree root 保存很多 BTree 的根节点。比如用户每建立一个快照,btrfs 便会创建一个 FS Tree 。为了管理所有的树,btrfs 采用 Tree of tree root 来保存所有树的根节点; checksum Tree 保存数据块的校验和。

基于 Extent 的文件存储

现代很多文件系统都采用了 extent 替代 block 来管理磁盘。 Extent 就是一些连续的 block,一个 extent 由起始的 block 加上长度进行定义。

Extent 能有效地减少元数据开销。为了进一步理解这个问题,我们还是看看 ext2 中的反面例子。

ext2/3 以 block 为基本单位,将磁盘划分为多个 block 。为了管理磁盘空间,文件系统需要知道哪些 block 是空闲的。 Ext 使用 bitmap 来达到这个目的。 Bitmap 中的每一个 bit 对应磁盘上的一个 block,当相应 block 被分配后,bitmap 中的相应 bit 被设置为 1 。这是很经典也很清晰的一个设计,但不幸的是当磁盘容量变大时,bitmap 自身所占用的空间也将变大。这就导致了扩展性问题,随着存储设备容量的增加,bitmap 这个元数据所占用的空间也随之增加。而人们希望无论磁盘容量如何增加,元数据不应该随之线形增加,这样的设计才具有可扩展性。

下图比较了 block 和 extent 的区别:

在 ext2/3 中,10 个 block 需要 10 个 bit 来表示;在 btrfs 中则只需要一个元数据。对于大文件,extent 表现出了更加优异的管理性能。

Extent 是 btrfs 管理磁盘空间的最小单位,由 extent tree 管理。 Btrfs 分配 data 或 metadata 都需要查询 extent tree 以便获得空闲空间的信息。

动态 inode 分配

为了理解动态 inode 分配,还是需要借助 ext2/3 。下表列举了 ext2 文件系统的限制:

限制最大文件数量文件系统空间大小 V / 8192

比如 100G 大小的文件系统中,能创建的文件个数最大为 131072

下图显示了 ext2 的磁盘布局:

在 ext2 中 inode 区是被预先固定分配的,且大小固定,比如一个 100G 的分区中,inode table 区中只能存放 131072 个 inode,这就意味着不可能创建超过 131072 个文件,因为每一个文件都必须有一个唯一的 inode 。

为了解决这个问题,必须动态分配 inode 。每一个 inode 只是 BTree 中的一个节点,用户可以无限制地任意插入新的 inode,其物理存储位置是动态分配的。所以 btrfs 没有对文件个数的限制。

针对 SSD 的优化支持

SSD 是固态存储 Solid State Disk 的简称。在过去的几十年中,CPU/RAM 等器件的发展始终遵循着摩尔定律,但硬盘 HDD 的读写速率却始终没有飞跃式的发展。磁盘 IO 始终是系统性能的瓶颈。

SSD 采用 flash memory 技术,内部没有磁盘磁头等机械装置,读写速率大幅度提升。 flash memory 有一些不同于 HDD 的特性。 flash 在写数据之前必须先执行擦除操作;其次,flash 对擦除操作的次数有一定的限制,在目前的技术水平下,对同一个数据单元最多能进行约 100 万次擦除操作,因此,为了延长 flash 的寿命,应该将写操作平均到整个 flash 上。

SSD 在硬件内部的微代码中实现了 wear leveling 等分布写操作的技术,因此系统无须再使用特殊的 MTD 驱动和 FTL 层。虽然 SSD 在硬件层面做了很多努力,但毕竟还是有限。文件系统针对 SSD 的特性做优化不仅能提高 SSD 的使用寿命,而且能提高读写性能。 Btrfs 是少数专门对 SSD 进行优化的文件系统。 btrfs 用户可以使用 mount 参数打开对 SSD 的特殊优化处理。

Btrfs 的 COW 技术从根本上避免了对同一个物理单元的反复写操作。如果用户打开了 SSD 优化选项,btrfs 将在底层的块空间分配策略上进行优化:将多次磁盘空间分配请求聚合成一个大小为 2M 的连续的块。大块连续地址的 IO 能够让固化在 SSD 内部的微代码更好的进行读写优化,从而提高 IO 性能。

数据一致性相关的特性

COW 事务

理解 COW 事务,必须首先理解 COW 和事务这两个术语。

所谓 COW,即每次写磁盘数据时,先将更新数据写入一个新的 block,当新数据写入成功之后,再更新相关的数据结构指向新 block 。

COW 只能保证单一数据更新的原子性。但文件系统中很多操作需要更新多个不同的元数据,比如创建文件需要修改以下这些元数据:

  1. 修改 extent tree,分配一段磁盘空间
  2. 创建一个新的 inode,并插入 FS Tree 中
  3. 增加一个目录项,插入到 FS Tree 中

任何一个步骤出错,文件便不能创建成功,因此可以定义为一个事务。

下面将演示一个 COW 事务。

A 是 FS Tree 的根节点,新的 inode 的信息将被插入节点 C 。首先,btrfs 将 inode 插入一个新分配的 block C ’中,并修改上层节点 B,使其指向新的 block C ’;修改 B 也将引发 COW,以此类推,引发一个连锁反应,直到最顶层的 Root A 。当整个过程结束后,新节点 A ’变成了 FS Tree 的根。但此时事务并未结束,superblock 依然指向 A 。

接下来,修改目录项(E 节点),同样引发这一过程,从而生成新的根节点 A ’’。

此时,inode 和目录项都已经写入磁盘,可以认为事务已经结束。 btrfs 修改 superblock,使其指向 A ’’,如下图所示:

COW 事务能够保证文件系统的一致性,并且系统 Reboot 之后不需要执行 fsck 。因为 superblock 要么指向新的 A ’’,要么指向 A,无论哪个都是一致的数据。

Checksum

Checksum 技术保证了数据的可靠性,避免 silent corruption 现象。由于硬件原因,从磁盘上读出的数据会出错。比如 block A 中存放的数据为 0x55,但读取出来的数据变是 0x54,因为读取操作并未报错,所以这种错误不能被上层软件所察觉。

解决这个问题的方法是保存数据的校验和,在读取数据后检查校验和。如果不符合,便知道数据出现了错误。

ext2/3 没有校验和,对磁盘完全信任。而不幸的是,磁盘的错误始终存在,不仅发生在廉价的 IDE 硬盘上,昂贵的 RAID 也存在 silent corruption 问题。而且随着存储网络的发展,即使数据从磁盘读出正确,也很难确保能够安全地穿越网络设备。

btrfs 在读取数据的同时会读取其相应的 checksum 。如果最终从磁盘读取出来的数据和 checksum 不相同,btrfs 会首先尝试读取数据的镜像备份,如果数据没有镜像备份,btrfs 将返回错误。写入磁盘数据之前,btrfs 计算数据的 checksum 。然后将 checksum 和数据同时写入磁盘。

Btrfs 采用单独的 checksum Tree 来管理数据块的校验和,把 checksum 和 checksum 所保护的数据块分离开,从而提供了更严格的保护。假如在每个数据 block 的 header 中加入一个域保存 checksum,那么这个数据 block 就成为一个自己保护自己的结构。这种结构下有一种错误无法检测出来,比如本来文件系统打算从磁盘上读 block A,但返回了 block B,由于 checksum 在 block 内部,因此 checksum 依旧是正确的。 btrfs 采用 checksum tree 来保存数据块的 checksum,避免了上述问题。

Btrfs 采用 crc32 算法计算 checksum,在将来的开发中会支持其他类型的校验算法。为了提高效率,btrfs 将写数据和 checksum 的工作分别用不同的内核线程并行执行。

多设备管理相关的特性

每个 Unix 管理员都曾面临为用户和各种应用分配磁盘空间的任务。多数情况下,人们无法事先准确地估计一个用户或者应用在未来究竟需要多少磁盘空间。磁盘空间被用尽的情况经常发生,此时人们不得不试图增加文件系统空间。传统的 ext2/3 无法应付这种需求。

很多卷管理软件被设计出来满足用户对多设备管理的需求,比如 LVM 。 Btrfs 集成了卷管理软件的功能,一方面简化了用户命令;另一方面提高了效率。

多设备管理

Btrfs 支持动态添加设备。用户在系统中增加新的磁盘之后,可以使用 btrfs 的命令将该设备添加到文件系统中。

为了灵活利用设备空间,Btrfs 将磁盘空间划分为多个 chunk 。每个 chunk 可以使用不同的磁盘空间分配策略。比如某些 chunk 只存放 metadata,某些 chunk 只存放数据。一些 chunk 可以配置为 mirror,而另一些 chunk 则可以配置为 stripe 。这为用户提供了非常灵活的配置可能性。

Subvolume

Subvolume 是很优雅的一个概念。即把文件系统的一部分配置为一个完整的子文件系统,称之为 subvolume 。

采用 subvolume,一个大的文件系统可以被划分为多个子文件系统,这些子文件系统共享底层的设备空间,在需要磁盘空间时便从底层设备中分配,类似应用程序调用 malloc() 分配内存一样。可以称之为存储池。这种模型有很多优点,比如可以充分利用 disk 的带宽,可以简化磁盘空间的管理等。

所谓充分利用 disk 的带宽,指文件系统可以并行读写底层的多个 disk,这是因为每个文件系统都可以访问所有的 disk 。传统的文件系统不能共享底层的 disk 设备,无论是物理的还是逻辑的,因此无法做到并行读写。

所谓简化管理,是相对于 LVM 等卷管理软件而言。采用存储池模型,每个文件系统的大小都可以自动调节。而使用 LVM,如果一个文件系统的空间不够了,该文件系统并不能自动使用其他磁盘设备上的空闲空间,而必须使用 LVM 的管理命令手动调节。

Subvolume 可以作为根目录挂载到任意 mount 点。 subvolume 是非常有趣的一个特性,有很多应用。

假如管理员只希望某些用户访问文件系统的一部分,比如希望用户只能访问 /var/test/ 下面的所有内容,而不能访问 /var/ 下面其他的内容。那么便可以将 /var/test 做成一个 subvolume 。 /var/test 这个 subvolume 便是一个完整的文件系统,可以用 mount 命令挂载。比如挂载到 /test 目录下,给用户访问 /test 的权限,那么用户便只能访问 /var/test 下面的内容了。

快照和克隆

快照是对文件系统某一时刻的完全备份。建立快照之后,对文件系统的修改不会影响快照中的内容。这是非常有用的一种技术。

比如数据库备份。假如在时间点 T1,管理员决定对数据库进行备份,那么他必须先停止数据库。备份文件是非常耗时的操作,假如在备份过程中某个应用程序修改了数据库的内容,那么将无法得到一个一致性的备份。因此在备份过程中数据库服务必须停止,对于某些关键应用这是不能允许的。

利用快照,管理员可以在时间点 T1 将数据库停止,对系统建立一个快照。这个过程一般只需要几秒钟,然后就可以立即重新恢复数据库服务。此后在任何时候,管理员都可以对快照的内容进行备份操作,而此时用户对数据库的修改不会影响快照中的内容。当备份完成,管理员便可以删除快照,释放磁盘空间。

快照一般是只读的,当系统支持可写快照,那么这种可写快照便被称为克隆。克隆技术也有很多应用。比如在一个系统中安装好基本的软件,然后为不同的用户做不同的克隆,每个用户使用自己的克隆而不会影响其他用户的磁盘空间。非常类似于虚拟机。

Btrfs 支持 snapshot 和 clone 。这个特性极大地增加了 btrfs 的使用范围,用户不需要购买和安装昂贵并且使用复杂的卷管理软件。下面简要介绍一下 btrfs 实现快照的基本原理。

如前所述 Btrfs 采用 COW 事务技术,从图 COW transaction 3 可以看到,COW 事务结束后,如果不删除原来的节点 A,C,E,那么 A,C,E,D,F 依然完整的表示着事务开始之前的文件系统。这就是 snapshot 实现的基本原理。

Btrfs 采用引用计数决定是否在事务 commit 之后删除原有节点。对每一个节点,btrfs 维护一个引用计数。当该节点被别的节点引用时,该计数加一,当该节点不再被别的节点引用时,该计数减一。当引用计数归零时,该节点被删除。对于普通的 Tree Root, 引用计数在创建时被加一,因为 Superblock 会引用这个 Root block 。很明显,初始情况下这棵树中的所有其他节点的引用计数都为一。当 COW 事务 commit 时,superblock 被修改指向新的 Root A ’’,原来 Root block A 的引用计数被减一,变为零,因此 A 节点被删除。 A 节点的删除会引发其子孙节点的引用计数也减一,图 COW transaction 3 中的 B,C 节点的引用计数因此也变成了 0,从而被删除。 D,E 节点在 COW 时,因为被 A ’’所引用,计数器加一,因此计数器这时并未归零,从而没有被删除。

创建 Snapshot 时,btrfs 将的 Root A 节点复制到 sA,并将 sA 的引用计数设置为 2 。在事务 commit 的时候,sA 节点的引用计数不会归零,从而不会被删除,因此用户可以继续通过 Root sA 访问 snapshot 中的文件。

软件 RAID

RAID 技术有很多非常吸引人的特性,比如用户可以将多个廉价的 IDE 磁盘组合为 RAID0 阵列,从而变成了一个大容量的磁盘; RAID1 和更高级的 RAID 配置还提供了数据冗余保护,从而使得存储在磁盘中的数据更加安全。

Btrfs 很好的支持了软件 RAID,RAID 种类包括 RAID0,RAID1 和 RAID10.

Btrfs 缺省情况下对 metadata 进行 RAID1 保护。前面已经提及 btrfs 将设备空间划分为 chunk,一些 chunk 被配置为 metadata,即只存储 metadata 。对于这类 chunk,btrfs 将 chunk 分成两个条带,写 metadata 的时候,会同时写入两个条带内,从而实现对 metadata 的保护。

其他特性

Btrfs 主页上罗列的其他特性不容易分类,这些特性都是现代文件系统中比较先进的技术,能够提高文件系统的时间或空间效率。

Delay allocation

延迟分配技术能够减少磁盘碎片。在 Linux 内核中,为了提高效率,很多操作都会延迟。

在文件系统中,小块空间频繁的分配和释放会造成碎片。延迟分配是这样一种技术,当用户需要磁盘空间时,先将数据保存在内存中。并将磁盘分配需求发送给磁盘空间分配器,磁盘空间分配器并不立即分配真正的磁盘空间。只是记录下这个请求便返回。

磁盘空间分配请求可能很频繁,所以在延迟分配的一段时间内,磁盘分配器可以收到很多的分配请求,一些请求也许可以合并,一些请求在这段延迟期间甚至可能被取消。通过这样的“等待”,往往能够减少不必要的分配,也有可能将多个小的分配请求合并为一个大的请求,从而提高 IO 效率。

Inline file

系统中往往存在大量的小文件,比如几百个字节或者更小。如果为其分配单独的数据 block,便会引起内部碎片,浪费磁盘空间。 btrfs 将小文件的内容保存在元数据中,不再额外分配存放文件数据的磁盘块。改善了内部碎片问题,也增加了文件的访问效率。

上图显示了一个 BTree 的叶子节点。叶子中有两个 extent data item 元数据,分别用来表示文件 file1 和 file2 所使用的磁盘空间。

假设 file1 的大小仅为 15 个字节; file2 的大小为 1M 。如图所示,file2 采用普通的 extent 表示方法:extent2 元数据指向一段 extent,大小为 1M,其内容便是 file2 文件的内容。

而对于 file1, btrfs 会把其文件内容内嵌到元数据 extent1 中。如果不采用 inline file 技术。如虚线所示,extent1 指向一个最小的 extent,即一个 block,但 file1 有 15 个字节,其余的空间便成为了碎片空间。

采用 inline 技术,读取 file1 时只需要读取元数据 block,而无需先读取 extent1 这个元数据,再读取真正存放文件内容的 block,从而减少了磁盘 IO 。

得益于 inline file 技术,btrfs 处理小文件的效率非常高,也避免了磁盘碎片问题。

Directory index

当一个目录下的文件数目巨大时,目录索引可以显著提高文件搜索时间。 Btrfs 本身采用 BTree 存储目录项,所以在给定目录下搜索文件的效率是非常高的。

然而,btrfs 使用 BTree 管理目录项的方式无法同时满足 readdir 的需求。 readdir 是 POSIX 标准 API,它要求返回指定目录下的所有文件,并且特别的,这些文件要按照 inode number 排序。而 btrfs 目录项插入 BTree 时的 Key 并不是 Inode number,而是根据文件名计算的一个 hash 值。这种方式在查找一个特定文件时非常高效,但却不适于 readdir 。为此,btrfs 在每次创建新的文件时,除了插入以 hash 值为 Key 的目录项外,还同时插入另外一种目录项索引,该目录项索引的 KEY 以 sequence number 作为 BTree 的键值。这个 sequence number 在每次创建新文件时线性增加。因为 Inode number 也是每次创建新文件时增加的,所以 sequence number 和 inode number 的顺序相同。以这种 sequence number 作为 KEY 在 BTree 中查找便可以方便的得到一个以 inode number 排序的文件列表。

另外以 sequence number 排序的文件往往在磁盘上的位置也是相邻的,所以以 sequence number 为序访问大量文件会获得更好的 IO 效率。

压缩

大家都曾使用过 zip,winrar 等压缩软件,将一个大文件进行压缩可以有效节约磁盘空间。 Btrfs 内置了压缩功能。

通常人们认为将数据写入磁盘之前进行压缩会占用很多的 CPU 计算时间,必然降低文件系统的读写效率。但随着硬件技术的发展,CPU 处理时间和磁盘 IO 时间的差距不断加大。在某些情况下,花费一定的 CPU 时间和一些内存,但却能大大节约磁盘 IO 的数量,这反而能够增加整体的效率。

比如一个文件不经过压缩的情况下需要 100 次磁盘 IO 。但花费少量 CPU 时间进行压缩后,只需要 10 次磁盘 IO 就可以将压缩后的文件写入磁盘。在这种情况下,IO 效率反而提高了。当然,这取决于压缩率。目前 btrfs 采用 zlib 提供的 DEFALTE/INFLATE 算法进行压缩和解压。在将来,btrfs 应该可以支持更多的压缩算法,满足不同用户的不同需求。

目前 btrfs 的压缩特性还存在一些不足,当压缩使能后,整个文件系统下的所有文件都将被压缩,但用户可能需要更细粒度的控制,比如针对不同的目录采用不同的压缩算法,或者禁止压缩。我相信,btrfs 开发团队将在今后的版本中解决这个问题。

对于某些类型的文件,比如 jpeg 文件,已经无法再进行压缩。尝试对其压缩将纯粹浪费 CPU 。为此,当对某文件的若干个 block 压缩后发现压缩率不佳,btrfs 将不会再对文件的其余部分进行压缩操作。这个特性在某种程度上提高了文件系统的 IO 效率。

预分配

很多应用程序有预先分配磁盘空间的需要。他们可以通过 posix_fallocate 接口告诉文件系统在磁盘上预留一部分空间,但暂时并不写入数据。如果底层文件系统不支持 fallocate,那么应用程序只有使用 write 预先写一些无用信息以便为自己预留足够的磁盘空间。

由文件系统来支持预留空间更加有效,而且能够减少磁盘碎片,因为所有的空间都是一次分配,因而更有可能使用连续的空间。 Btrfs 支持 posix_fallocate 。

总结

至此,我们对 btrfs 的很多特性进行了较为详细的探讨,但 btrfs 能提供的特性却并不止这些。 btrfs 正处于试验开发阶段,还将有更多的特性。

Btrfs 也有一个重要的缺点,当 BTree 中某个节点出现错误时,文件系统将失去该节点之下的所有的文件信息。而 ext2/3 却避免了这种被称为”错误扩散”的问题。

但无论怎样,希望您和我一样,开始认同 btrfs 将是 Linux 未来最有希望的文件系统。

Btrfs 使用

了解了 btrfs 的特性,想必您一定想亲身体验一下 btrfs 的使用。本章将简要介绍如何使用 btrfs 。

要使用一些用户空间工具的话,需要 安装 基础操作必须的 btrfs-progs 软件包。

停用写时复制 (CoW)

chattr +C /dir/file会为这个文件的单个引用停用写时复制,如果这个文件不只有一个引用(例如通过 cp 生成或者在文件系统快照中),写时复制依然生效。

可以用下面的方法为已存在的文件或目录停用写时复制:

$ mv /path/to/dir /path/to/dir_old
$ mkdir /path/to/dir
$ chattr +C /path/to/dir
$ cp -a --reflink=never /path/to/dir_old/. /path/to/dir
$ rm -rf /path/to/dir_old
创建文件系统

单一设备上的文件系统

要在分区 /dev/partition 上创建一个 Btrfs 文件系统,执行:

# mkfs.btrfs -L mylabel /dev/partition

Btrfs 用于元数据的默认节点大小 (nodesize) 为 16KB,而用于数据的默认扇区大小 (sectorsize) 等于页面大小 (page size) 并会自动检测。 要对元数据使用较大的节点大小 (必须为扇区大小的倍数,最大允许 64KB),请通过 -n 开关为 nodesize 指定一个值。如下例所示,使用 32KB 块大小:

# mkfs.btrfs -L mylabel -n 32k /dev/partition

注意: 根据 mkfs.btrfs(8) § OPTIONS 手册页内容:“较小的节点大小会增加碎片,但也会让 B-trees 更高,进而使得锁定争用(locking contention)更少。较高的节点大小则能有更好的打包(packing)和更少的碎片,但代价是,更新元数据块时会使用更多的内存”。

多设备文件系统 RAID

多个设备可以用来创建一组 RAID。支持的 RAID 级别有 RAID 0、RAID 1、RAID 10、RAID 5 和 RAID 6。从 5.5 版本内核开始,新增对 RAID1c3RAID1c4 的支持,分别是 3 份冗余和 4 份冗余的 RAID 1。可以使用 -d-m 参数分别为数据和元数据配置 RAID 等级。默认情况下,数据有一份副本(single),元数据则被镜像(RAID1)。

# mkfs.btrfs -d single -m raid1 /dev/part1 /dev/part2 ...
subvolume

创建子卷

要创建一个子卷:

# btrfs subvolume create /path/to/subvolume

列出子卷列表

要列出当前路径 (path) 下的子卷和它们的 ID:

# btrfs subvolume list -p path

删除子卷

要删除一个子卷:

# btrfs subvolume delete /path/to/subvolume

自 Linux 4.18 起, 用户可以像移除常规目录一样删除一个子卷 (用 rm -r, rmdir 命令)。

挂载子卷

可以使用 subvol=*/path/to/subvolume*subvolid=*objectid* 挂载标志来安装子卷,就像文件系统分区一样。

$ sudo mount /dev/sdb1 -o subvol=projects /tmp/projects$ sudo mount /dev/sdb1 -o subvolid=261 /tmp/projects
使用 Btrfs 快照进行增量备份

*快照(snapshot)*是 Btrfs 的一个有趣的功能。快照是一个子卷的副本。生成快照是立即的。然而,生成快照与执行 rsynccp 不同,快照并不是一创建就会占用空间。

编者注:来自 BTRFS Wiki:快照简单的来说就是一个子卷,它使用 Btrfs 的 COW 功能与其他子卷共享其数据(和元数据)。

占用的空间将随着原始子卷或快照本身(如果它是可写的)的数据变化而增加。子卷中已添加/修改的文件和已删除的文件仍然存在于快照中。这是一种方便的备份方式。

使用快照进行备份

快照驻留在子卷所在的同一磁盘上。你可以像浏览普通目录一样浏览它,并按照生成快照时的状态恢复文件的副本。顺便说一下,在快照子卷的同一磁盘上生成快照并不是一个理想的备份策略:如果硬盘坏了,快照也会丢失。快照的一个有趣的功能是可以将快照发送到另一个位置。快照可以被发送到外部硬盘或通过 SSH 发送到远程系统(目标文件系统也需要格式化为 Btrfs)。要实现这个,需要使用命令 btrfs sendbtrfs receive

生成快照

要使用 btrfs sendbtrfs receive 命令,重要的是要将快照创建为只读,而快照默认是可写的。

要创建一个快照:

# btrfs subvolume snapshot source [dest/]name

source为要创建快照的对象,[dest/]name为快照安放路径。

下面的命令将对 /home 子卷进行快照。请注意 -r 标志代表只读。

sudo btrfs subvolume snapshot -r /home /.snapshots/home-day1

快照的名称可以是当前日期,而不是 day1,比如 home-$(date +%Y%m%d)。快照看起来像普通的子目录。你可以把它们放在任何你喜欢的地方。目录 /.snapshots 可能是一个不错的选择,以保持它们的整洁和避免混淆。

编者注:快照不会对自己进行递归快照。如果你创建了一个子卷的快照,子卷所包含的每一个子卷或快照都会被映射到快照里面的一个同名的空目录。

使用 btrfs send 进行备份

在本例中,U 盘中的目标 Btrfs 卷被挂载为 /run/media/user/mydisk/bk。发送快照到目标卷的命令是:

sudo btrfs send /.snapshots/home-day1 | sudo btrfs receive /run/media/user/mydisk/bk

这被称为初始启动,它相当于一个完整的备份。这个任务需要一些时间,取决于 /home 目录的大小。显然,后续的增量发送只需要更短的时间。

增量备份

快照的另一个有用的功能是能够以增量的方式执行发送任务。让我们再来生成一个快照。

sudo btrfs subvolume snapshot -r /home /.snapshots/home-day2

为了执行增量发送任务,需要指定上一个快照作为基础,并且这个快照必须存在于源文件和目标文件中。请注意 -p 选项。

sudo btrfs send -p /.snapshot/home-day1 /.snapshot/home-day2 | sudo btrfs receive /run/media/user/mydisk/bk

再来一次(一天之后):

sudo btrfs subvolume snapshot -r /home /.snapshots/home-day3sudo btrfs send -p /.snapshot/home-day2 /.snapshot/home-day3 | sudo btrfs receive /run/media/user/mydisk/bk

清理

操作完成后,你可以保留快照。但如果你每天都执行这些操作,你可能最终会有很多快照。这可能会导致混乱,并可能会在你的磁盘上使用大量的空间。因此,如果你认为你不再需要一些快照,删除它们是一个很好的建议。

请记住,为了执行增量发送,你至少需要最后一个快照。这个快照必须存在于源文件和目标文件中。

sudo btrfs subvolume delete /.snapshot/home-day1sudo btrfs subvolume delete /.snapshot/home-day2sudo btrfs subvolume delete /run/media/user/mydisk/bk/home-day1sudo btrfs subvolume delete /run/media/user/mydisk/bk/home-day2

注意:第 3 天的快照被保存在源文件和目标文件中。这样,明天(第 4 天),你就可以执行新的增量 btrfs send

最后的建议是,如果 U 盘的空间很大,可以考虑在目标盘中保留多个快照,而在源盘中只保留最后一个快照。

压缩

给现存文件启用压缩,可使用 btrfs filesystem defragment -c alg 命令,alg 处可选填为 zliblzozstd。举例来说,要用 zstd 方式给整个文件系统重新压缩,执行下列命令:

# btrfs filesystem defragment -r -v -c zstd /

要在新的 Btrfs 分区上安装 Arch Linux 时就启用压缩功能 (充分利用压缩特性),请在 挂载 文件系统时使用 compress 选项:mount -o compress=zstd /dev/sd*xY* /mnt/。在配置过程中,请在 fstab 中把 compress=zstd 添加到根目录文件系统的挂载选项里。

提示: 通过执行 chattr +c,也可以在不使用 compress 选项的情况下为每个单文件启用压缩属性。对目录执行会使这个目录下新文件自动被压缩。

Btrfs 和 LVM-ext4

两者的共性

尽管两个文件系统之间存在核心差异,但 Btrfs 和 LVM-ext4 实际上有很多共同之处。两者都是成熟且经过充分测试的存储技术。从 Fedora Core 的早期开始,就一直在使用 LVM,而 ext4 在 2009 年成为 Fedora 11 的默认设置。Btrfs 在 2009 年并入 Linux 主线内核,并且 Facebook 广泛使用了该文件系统。SUSE Linux Enterprise 12 在 2014 年使其成为默认文件系统。因此,它在生产环境中也有着长久的运行时间。

这两个系统都能很好地防止因意外停电而导致的文件系统损坏,尽管它们的实现方式不同。它们支持的配置包括使用单盘设置和跨越多个设备,并且这两种配置都能够创建近乎即时的快照。有各种工具可以帮助管理这两种系统,包括命令行和图形界面。这两种解决方案在家用台式机和高端服务器上都同样有效。

LVM-ext4 的优势

ext4 文件系统 专注于高性能和可伸缩性,没有太多额外的花哨之处。它能有效地防止长时间后的碎片化,并当碎片化出现后提供了 很好的工具。ext4 之所以坚如磐石,是因为它构建在前代的 ext3 文件系统之上,带来了多年的系统内测试和错误修复。

LVM-ext4 环境中的大多数高级功能都来自 LVM 本身。LVM 位于文件系统的“下方”,这意味着它支持任何文件系统。逻辑卷Logical volume(LV)是通用的块设备,因此 虚拟机可以直接使用它们。这种灵活性使得每个逻辑卷都可以使用合适的文件系统,用合适的选项应对各种情况。这种分层方法还遵循了“小工具协同工作”的 Unix 哲学。

从硬件抽象出来的卷组volume group(VG)允许 LVM 创建灵活的逻辑卷。每个逻辑卷都提取自同一个存储池,但具有自己的设置。调整卷的大小比调整物理分区的大小容易得多,因为没有数据有序放置的限制。LVM 物理卷physical volume(PV)可以是任意数量的分区,甚至可以在系统运行时在设备之间移动。

LVM 支持只读和读写的 快照,这使得从活动系统创建一致的备份变得很容易。每个快照都有一个定义的大小,更改源卷或快照卷将占用其中的空间。又或者,逻辑卷也可以是稀疏配置池thinly provisioned pool的一部分。这允许快照自动使用池中的数据,而不是使用在创建卷时定义的固定大小的块。

有多个磁盘驱动器的 LVM

当有多个设备时,LVM 才真正大放异彩。它原生支持大多数 RAID 级别,每个逻辑卷可以具有不同的 RAID 级别。LVM 将自动为 RAID 配置选择适当的物理设备,或者用户可以直接指定它。基本的 RAID 支持包括用于性能的数据条带化(RAID0)和用于冗余的镜像(RAID1)。逻辑卷也可以使用 RAID5RAID6RAID10 等高级设置。LVM RAID 支持已经成熟,因为 LVM 在底层使用的 设备映射器(dm)多设备(md) 内核支持, 与 mdadm 使用的一样。

对于具有快速和慢速驱动器的系统,逻辑卷也可以是 缓存卷。经典示例是 SSD 和传统磁盘驱动器的组合。缓存卷使用较快的驱动器来存储更频繁访问的数据(或用作写缓存),而慢速的驱动器则用于处理大量数据。

LVM 中大量稳定的功能以及 ext4 的可靠性在既往的使用中早已被证明了。当然,功能越多就越复杂。在配置 LVM 时,要找到合适的功能选项是很有挑战性的。对于单驱动器的台式机系统,LVM 的功能(例如 RAID 和缓存卷)不适用。但是,逻辑卷比物理分区更灵活,快照也很有用。对于正常的桌面使用,LVM 的复杂性会成为典型的用户可能遇到的问题恢复的障碍。

Btrfs 的优势

从前几代文件系统中学到的经验指导了构建到 Btrfs 的功能设计。与 ext4 不同,它可以直接跨越多个设备,因此它具有通常仅在卷管理器中才能找到的功能。它还具有 Linux 文件系统空间中独有的功能(ZFS 具有相似的功能集,但不要指望它在 Linux 内核中出现)。

Btrfs 的主要功能

也许最重要的功能是对所有数据进行校验和checksumming。校验和与写时复制copy-on-write(COW)一起,提供了在意外断电后确保文件系统完整性的 关键方法。更独特的是,校验和可以检测数据本身中的错误。悄然的数据损坏(有时也称为 bitrot)比大多数人意识到的更常见。如果没有主动验证,损坏最终可能会传播到所有可用的备份中。这使得用户没有有效的副本。通过透明地校验所有数据,Btrfs 能够立即检测到任何此类损坏。启用正确的 dup 或 raid 选项,文件系统也可以透明地修复损坏。

写时复制也是 Btrfs 的基本功能,因为它在提供文件系统完整性和即时子卷快照方面至关重要。从公共子卷创建快照后,快照会自动共享底层数据。另外,事后的重复数据删除deduplication 使用相同的技术来消除相同的数据块。单个文件可以通过使用 cpreflink 选项 来使用 COW 功能。reflink 副本对于复制大型文件(例如虚拟机镜像)特别有用,这些文件往往随着时间的推移具有大部分相同的数据。

Btrfs 支持跨越多个设备,而无需卷管理器。多设备支持可提供数据镜像功能以实现冗余和条带化以提高性能。此外,还实验性地支持更高级的 RAID 级别,例如 RAID 5RAID 6。与标准 RAID 设置不同,Btrfs 的 RAID1 实际上允许奇数个设备。例如,它可以使用 3 个设备,即使它们的大小不同。

所有 RAID 和 dup 选项都是在文件系统级别指定的。因此,各个子卷不能使用不同的选项。请注意,使用多设备的 RAID1 选项意味着即使一个设备发生故障,卷中的所有数据都是可用的,并且校验功能可以保持数据本身的完整性。这超出了当前典型的 RAID 设置所能提供的范围。

附加功能

Btrfs 还支持快速简便的远程备份。子卷快照可以 发送到远程系统 进行存储。通过利用文件系统中固有的 COW 元数据,这些传输通过仅发送先前发送的快照中的增量更改而非常有效。诸如 snapper 之类的用户应用程序使管理这些快照变得容易。

另外,Btrfs 卷可以具有 透明压缩 功能,并且 chattr +c 可以标记进行压缩的单个文件或目录。压缩不仅可以减少数据消耗的空间,还可以通过减少写入操作量来帮助延长 SSD 的寿命。压缩当然会带来额外的 CPU 开销,但是有很多选项就可以权衡取舍。

Btrfs 集成了文件系统和卷管理器功能,这意味着总体维护比 LVM-ext4 更简单。当然,这种集成的灵活性较低,但是对于大多数台式机甚至服务器而言,设置已足够。

LVM 上使用 Btrfs

Btrfs 可以 就地转换 ext3/ext4 文件系统。就地转换意味着无需将数据复制出来然后再复制回去。数据块本身甚至都不需要修改。因此,对于现有的 LVM-ext4 系统,一种选择是将 LVM 保留在原处,然后简单地将 ext4 转换为 Btrfs。虽然可行且受支持,但有一些原因使它不是最佳选择。

Btrfs 的吸引力之一是与卷管理器集成的文件系统所带来的更轻松的管理。要是在 LVM 之上运行,对于系统维护,仍然要对额外的卷管理器进行一些设置。同样,LVM 设置通常具有多个固定大小的逻辑卷,并具有独立文件系统。虽然 Btrfs 支持给定的计算机上的多个卷,但是许多不错的功能都需要单一卷具有多个子卷。如果每个 LVM 卷都有一个独立的 Btrfs 卷,则用户仍然需要手动管理固定大小的 LVM 卷。虽然能够收缩挂载的 Btrfs 文件系统的能力确实使处理固定大小的卷的工作变得更轻松。通过在线收缩功能,就无需启动 实时镜像 了。

在使用 Btrfs 的多设备支持时,必须仔细考虑逻辑卷的物理位置。对于 Btrfs 而言,每个逻辑卷都是一个单独的物理设备,如果实际情况并非如此,则某些数据可用性功能可能会做出错误的决定。例如,如果单个驱动器发生故障,对数据使用 RAID1 通常可以提供保护。如果实际逻辑卷在同一物理设备上,则没有冗余。

如果强烈需要某些特定的 LVM 功能,例如原始块设备或高速缓存的逻辑卷,则在 LVM 之上运行 Btrfs 是有意义的。在这种配置下,Btrfs 仍然提供其大多数优点,例如校验和和易于发送的增量快照。尽管使用 LVM 会产生一些操作开销,但 Btrfs 的这种开销并不比任何其他文件系统大。

总结

当尝试在 Btrfs 和 LVM-ext4 之间进行选择时,没有一个正确的答案。每个用户都有独特的要求,并且同一用户可能拥有具有不同需求的不同系统。看一下每个配置的功能集,并确定是否有令人心动的功能。如果没有,坚持默认值没有错。选择这两种设置都有很好的理由。

Snapper

Snapper 是 openSUSE 下用于创建和管理文件系统快照(以下简称快照)的工具。快照保存了文件系统在某个时间点的状态,从而可以轻松实现系统回滚或数据备份。

Snapper 可以在 Btrfs 文件系统(推荐)及采用 XFS 或 Ext4 文件系统的 LVM 精简配置卷上使用,本文主要介绍在 Btrfs 文件系统上使用 Snapper 的方法。

快照类型

Snapper 快照可分为两大类型:

  • 快照对:由一对快照组成,在进行某项操作前拍摄一个“前快照”(pre),操作后再拍摄一个“后快照”(post),从而可以比较两个快照对差异而撤销该操作。快照对是一一对应的,如果删除了某一快照,则对应的快照也会被删除。
  • 单一快照(single):由一个单独的快照组成,与其他快照没有特殊联系。可用于备份或回滚整个系统等操作。

快照对和单一快照既可以手动创建,也可以根据配置自动创建。自动创建的快照又可分为三种类型:

  • 时间线快照:每小时自动创建的单一快照。
  • 安装快照:在安装软件包前后自动创建的一对快照对。可用于撤销软件包更改。
  • 管理快照:在使用 YaST 管理系统前后自动创建的一堆快照对。可用于撤销配置更改。

这三种自动创建的快照均可单独启用和配置,从而提供了极大的灵活性。

默认配置

要在分区或 Btrfs 子卷启用快照,需要创建配置文件。Snapper 的配置文件存储在 /etc/snapper/configs 中。

如果你的根分区大于 16 GB,并且在安装 openSUSE 时使用默认分区配置,则根分区的配置文件应已被自动创建。默认配置启用了安装快照和管理快照,并排除了部分目录,可以满足大多数需求。以下列表显示了排除的所有目录:

  • /boot/grub2/i386-pc/boot/grub2/x86_64-efi/boot/grub2/powerpc-ieee1275/boot/grub2/s390x-emu

    不能回滚引导加载程序配置。上面列出的目录是架构专属目录。前两个目录位于 AMD64/Intel 64 计算机上,后两个目录分别位于 IBM POWER 和 IBM Z 上。

  • /home

    如果独立的分区中没有 /home,便会将该目录排除以免在回滚时发生数据丢失。

  • /opt/var/opt

    第三方产品通常安装到 /opt 下。排除此目录是为了防止在回滚时卸装这些应用程序。

  • /srv

    包含 Web 和 FTP 服务器的数据。排除此目录是为了防止在回滚时发生数据丢失。

  • /tmp/var/tmp/var/cache/var/crash

    包含临时文件和超速缓存的所有目录都会排除在快照范围之外。

  • /usr/local

    在手动安装软件时会用到此目录。系统会将该目录排除以免在回滚时卸载这些安装的软件。

  • /var/lib/libvirt/images

    使用 libvirt 管理的虚拟机映像的默认位置。为确保回滚期间虚拟机映像不会替换为旧版本而被排除。默认情况下,此子卷是使用写入时不复制选项创建的。

  • /var/lib/mailman/var/spool

    包含邮件或邮件队列的目录会排除,以免在回滚后造成邮件丢失。

  • /var/lib/bind

    包含 DNS 服务器的区域数据。排除该目录是为了确保回滚后名称服务器仍能运作。

  • /var/lib/mariadb/var/lib/mysql/var/lib/pgqsl

    这些目录包含数据库数据。默认情况下,这些子卷是使用写入时不复制选项创建的。

  • /var/log

    日志文件所在的位置。排除该目录是为了在对受损的系统进行回滚后能够对日志文件进行分析。

如果你希望使用 openSUSE 的默认配置,但在安装 openSUSE 时未开启快照功能,可以使用以下命令创建根分区的默认配置文件:

注意: 要使用该默认配置文件,请确保根分区大小至少为 16 GB,并使用 openSUSE 安装程序建议的包含子卷的 Btrfs 根文件系统(安装程序默认分区设置)

snapper -c root create-config /

确保 snapper-zypp-plugin 软件包已安装以启用安装快照:

zypper install snapper-zypp-plugin

手动配置

创建和装入新子卷

系统支持在 / 层次下创建新的子卷,并永久性装入该卷。此类子卷将从快照中排除。切勿在现有快照中创建此类子卷,因为在回滚之后,您将无法再删除快照。

SUSE Linux Enterprise Server 上配置了 /@/ 子卷,该子卷充当永久性子卷(例如 /opt/srv/home 等)的独立根目录。您创建和永久装入的任何新子卷都需要在这个初始根文件系统中创建。

为此,请运行以下命令。在此示例中,从 /dev/sda2 创建了一个新子卷 /usr/important

sudo mount /dev/sda2 -o subvol=@ /mntsudo btrfs subvolume create /mnt/usr/importantsudo umount /mnt

/etc/fstab 中的相应项需类似于:

/dev/sda2 /usr/important btrfs subvol=@/usr/important 0 0

提示:子卷可能包含经常更改的文件,例如虚拟化的磁盘映像、数据库文件或日志文件。如果是这样,可考虑对此卷禁用写入时复制功能,以免复制磁盘块。可在 /etc/fstab 中使用 nodatacow 装入选项来实现此目的:

/dev/sda2 /usr/important btrfs nodatacow,subvol=@/usr/important 0 0

或者,要为单个文件或目录禁用写入时复制功能,请使用命令 chattr +C 路径

创建配置文件

希望在特定分区或子卷启用快照,可以以下命令创建相应的配置文件:

snapper -c 配置文件名 create-config 分区或子卷的挂载点

这将根据 /etc/snapper/config-templates/default 提供的默认值创建配置文件。

注意: 在创建配置文件前请确保目标分区或子卷已被创建。不能为同一分区或子卷创建多个配置文件。

例如,为防止回滚时数据丢失,默认的根分区配置排除了 /home 目录,可以使用上述命令为 /home 创建配置文件:

snapper -c home create-config /home

该命令会使用 /etc/snapper/config-templates/default 提供的默认值创建 /etc/snapper/configs/home 文件。

可以使用

snapper list-configs

查看现有配置文件。

启用/禁用自动快照

你可以选择性地启用/禁用自动创建的快照类型:

启用时间线快照

snapper -c 配置文件名 set-config "TIMELINE_CREATE=yes"

禁用时间线快照

snapper -c 配置文件名 set-config "TIMELINE_CREATE=no"

时间线快照默认会启用,但根分区除外。

注意: 以下两种快照包含的内容由安装的软件包或修改的配置而定,与特定分区或子卷无关。默认为启用状态。

启用安装快照

zypper install snapper-zypp-plugin

禁用安装快照

zypper remove snapper-zypp-plugin

使用 YaST 或 Zypper 安装包时所创建的快照会由 snapper-zypp-plugin 进行处理。何时创建快照由 XML 配置文件 /etc/snapper/zypp-plugin.conf 定义。

启用管理快照

在 /etc/sysconfig/yast2 中将 USE_SNAPPER 设置为 yes

禁用管理快照

在 /etc/sysconfig/yast2 中将 USE_SNAPPER 设置为 no
配置文件参数

Snapper 的行为由配置文件参数定义,除了直接使用文本编辑器编辑配置文件外,还可以使用

snapper -c 配置文件名称 set-config "参数名称=参数"

修改配置文件参数。

以下对几个常用配置案例进行说明,完整的参数说明可参阅 snapper-configs(5) :

man snapper-configs

允许普通用户管理快照

默认情况下仅 root 用户可以管理快照,要允许普通用户或组管理快照,可运行:

snapper -c 配置文件名称 set-config "ALLOW_USERS=用户名" "ALLOW_GROUPS=组名" "SYNC_ACL=yes"

必须配置“SYNC_ACL=yes”以允许普通用户访问快照所在目录。

自动清理旧快照

为防止快照占据全部磁盘空间,Snapper 提供了几种自动清理旧快照的机制,可通过一系列参数配置自动清理过程:

清理机制 说明 启用选项 配置参数 含义 备注
编号 根据快照编号进行清理 NUMBER_CLEANUP=yes NUMBER_LIMIT=数字或范围 定义要保留的快照数量。 如果启用了定额支持,应使用范围。如果未启用定额支持,应使用单个数字。
NUMBER_LIMIT_IMPORTANT=数字或范围 定义要保留的含 important 标签的快照数量,内核更新等的安装快照自带该标签。
NUMBER_MIN_AGE=秒 定义满足上述条件的快照被清理前最少应保留的时间。0 表示无限制。
时间线 根据快照创建时间进行清理 TIMELINE_CLEANUP=yes TIMELINE_LIMIT_HOURLY=数字或范围 定义要保留的每小时首张快照的数量。 如果启用了定额支持,应使用范围。如果未启用定额支持,应使用单个数字。
TIMELINE_LIMIT_DAILY=数字或范围 定义要保留的每日首张快照的数量。
TIMELINE_LIMIT_WEEKLY=数字或范围 定义要保留的每周首张快照的数量,此处的周由星期一开始。
TIMELINE_LIMIT_MONTHLY=数字或范围 定义要保留的每月首张快照的数量。
TIMELINE_LIMIT_YEARLY=数字或范围 定义要保留的每年首张快照的数量。
TIMELINE_MIN_AGE=秒 定义满足上述条件的快照被清理前最少应保留的时间。0 表示无限制。
无差异快照对 清理没有差异的快照对。如运行 Yast2 后未作任何修改,则自动清理创建的管理快照。 EMPTY_PRE_POST_CLEANUP=yes EMPTY_PRE_POST_CLEANUP=秒 定义无差异快照对被清理前最少应保留的时间。0 表示无限制。
磁盘定额 定义快照可占用空间的百分比 运行snapper setup-quota SPACE_LIMIT=表示百分比的小数 定义快照可占用空间的百分比 仅支持 Btrfs 文件系统需至少启用编号或时间线清理算法中的一个启用定额支持后,编号和时间线清理算法的部分参数应当使用范围值。清理算法会清理快照至上限值,如果未满足定额配置则在下限值范围内尽量清理快照以满足定额。
管理配置文件

可以使用 snapper 命令快速管理配置文件:

列出配置文件

snapper list-configs

显示特定的配置文件

snapper -c 配置文件名称 get-config

删除配置文件

snapper -c 配置文件名称 delete-config

快照管理

可以使用 snapper 工具或 Yast2 模块进行查看、创建、比较快照等操作。

snapper 工具提供了一系列子命令,可以在文本界面进行快照管理。本节介绍了一些常用命令和参数,更多信息可参阅 snapper(8):

man snapper

注意: 管理快照时可使用 “-c 配置文件名” 指定配置文件,如未指定则默认使用 root 配置文件,下述示例均未指定配置文件。

查看快照

snapper list

将列出 root 配置的所有快照。

可以使用 “-t” 参数列出特定类型的快照。

例如,列出 root 配置下的所有快照对:

snapper list -t pre-post

列出 home 配置下的所有单一快照:

snapper -c home list -t single

你还可以使用

snapper list -a

列出所有配置下的快照。

创建快照

snapper create

将使用 root 配置文件创建一个单一快照。

可以使用“-t”参数指定快照类型(默认值为 single),使用“-d”参数添加描述。手动创建的快照默认不会自动被清理,使用“–cleanup-algorithm”参数指定自动清理算法。还可以使用“–userdata”参数定义自定义数据(如 important 标记)。

例如,创建当前系统的单一快照,标记为重要,并指定时间线清理算法:

snapper create -t single --description "系统快照" --userdata "important=yes" --cleanup-algorithm timeline

要创建一个快照对,首先创建一个前快照,使用“–print-number”选项以列出快照编号:

snapper create -t pre --print-number --description "Before"

假设列出的快照编号为 30,将其作为“–pre-number”参数的值创建后快照:

snapper create -t post --pre-number 30 --description "After"

你也可以使用

snapper create --command "要运行的命令"

以自动创建运行命令前后的快照对。

比较快照

有两种比较方法:

snapper status <第一个快照编号>..<第二个快照编号> //第一个快照的创建时间要早于第二个

将显示您在两个快照时间内修改的全部文件的路径和文件名。

例如,下述命令可以比较当前系统状态与 161 号快照的差异:

snapper status 161..0 //0 表示当前系统,它不是快照,但你可以认为是比所有快照都新的一个快照。

第二种:

snapper diff <第一个快照编号>..<第二个快照编号> 文件名

将以 diff 的格式显示指定文件的差异,如果未指定文件名,将显示所有文件的差异。

撤销修改

snapper undochange <修改前的快照编号>..<修改后的快照编号> <文件名>

比如你误删除了某个文件,可以使用:

snapper undochange <删除文件前的快照编号>..0 文件名 //0 表示当前系统,它不是快照,但你可以认为是比所有快照都新的一个快照。

来撤销。

删除快照

snapper delete 快照编号或范围

例如,要删除 16 号快照:

snapper delete 16

要删除 10 号到 15 号快照:

snapper delete 10-15

可以结合“-s”参数以在删除快照后立刻释放可用空间而不必等待 Btrfs 进程回收。

回滚整个系统

SUSE Linux Enterprise Server 上包含的 GRUB 2 版本可以从 Btrfs 快照进行引导。与 Snapper 的回滚功能相结合,就能恢复配置错误的系统。只有针对默认 Snapper 配置()创建的快照才可引导。

注意: 要回滚整个系统,请确保根文件系统为 openSUSE 安装程序默认的带子卷的 Btrfs 文件系统。从 SUSE Linux Enterprise Server 15 开始,只有在根分区的默认子卷配置未更改过的情况下,才支持系统回滚。

如果因为更新或病毒等原因导致系统出现重大错误,并保留了错误前的快照,则可以回滚整个系统到错误前的状态。

snapper rollback 要回滚的快照编号

该命令将创建当前系统状态的只读快照 A 及指定编号快照的可读写快照 B,并使用快照 B 替换根分区的默认子卷,重新启动系统后即可实现回滚。

你还可以在引导系统时选择Start bootloader from a read-only snapshot,以引导想要回滚的快照,在检查无误后在引导的快照中执行:

snapper rollback

不指定快照编号时,将创建根分区默认子卷(即原系统)的只读快照 A 和当前系统(即目前引导的快照)的可读写快照 B,并使用快照 B 替换根分区的默认子卷,重新启动系统后选择默认引导项即可实现回滚。

Tips

为什么选择 openSUSE

Free and Open Source

确定你心目中的贡献者们是什么样的,从而聚拢到这样的人。

狭义的自由开源概念

狭义的自由开源概念是:自由地开放源代码。即:软件作者把源代码公开发布,给予你修改并二次发布的权利。就这样,没别的了。

测试、调试、故障受理与修复、接受新功能请求、接受代码合并请求、接受别人的帮助、用户社区建立、互动、整个自由开源生态的维护,统统都是完全没有,谁愿意干谁干,跟我没有关系。或者这么说:“写完拉倒”,哪怕洪水滔天。这从 GPL 许可证的“无保声明”中可以看出端倪。

广义的自由开源概念

实际上如果你看过操作系统革命你就会明白:开放源代码其实并不是这一运动想要实现的全部,它的最终目的是普及自由精神,建立自由社区。

目前这一精神在自由开源软件上的表现有:

  • 源代码开源。
  • 来自软件所有者的开发门槛为零。
  • 不重新发明轮子。如果有已有实现并可以扩展,那么扩展它。
  • 文档开源。使用维基等。
  • 组织并形成用户互助社区。积极帮助用户(在不影响开发的前提下)。同时在开发上尽量面向用户,把用户的反应纳入到重大修改的考量因素当中去,积极采纳合理意见。
  • 积极回应故障汇报并提供修复。
  • 积极回应新功能请求。能做的做,不能做的解释原因寻求理解。
  • 形成良性的贡献者添加内容和用户反馈渠道。
  • 重视并维护由类似软件共同组成的生态的和谐稳定。(简单说就是:我开发 KDE 是因为 GNOME 满足不了我的需求,而不是为了搞死 GNOME。)

现在您可以拿来同狭义的自由开源概念做比较,发现如果说狭义的自由开源概念只是指某种行为,那么广义的自由开源概念已经是指一种氛围了。

openSUSE 秉持的自由开源概念

openSUSE 项目是完全做到“广义的自由开源概念”的社区

同时我们一直持有的相关理念还有:

  • 积极的与上游合作。不“内化”补丁或修改,除非上游出于种种原因不收。
  • 积极的为整个生态着想。
  • 不搞歧视或二等公民。
  • 尊重许可证、版权甚至是专利

如果你认同这些,那么您适合这个社区。

Remove a file using inode number

用 7zip 解压出一个乱码文件,删除不了,因此考虑用 inode 删除。

  1. Use -i flag to get the inode number of any file (First column is your inode)

    $ ls -li
    
  2. In find command, use -inum flag with inode number and ls at the end to list a file

    $ find . -inum <inode number> -ls
    
  3. In find command, use -inum flag with inode number and pass the rm using exec arugment to delete a file

    $ find . -inum <inode number> -exec rm {} \;
    

乱码问题

Unicode 中文乱码速查表

xxxxxx 示例 特点 产生原因
古文码 鐢辨湀瑕佸ソ濂藉涔犲ぉ澶╁悜涓? 大都为不认识的古文,并加杂日韩文 以 GBK 方式读取 UTF-8 编码的中文
口字码 ����Ҫ�¨2�ѧϰ������ 大部分字符为小方块 以 UTF-8 的方式读取 GBK 编码的中文
符号码 由月è|�好好å-|ä1 天天å�‘上 大部分字符为各种符号 以 ISO8859-1 方式读取 UTF-8 编码的中文
拼音码 óéÔÂòaoÃoÃѧϰììììÏòéÏ 大部分字符为头顶带有各种类似声调符号的字母 以 ISO8859-1 方式读取 GBK 编码的中文
问句码 由月要好好学习天天向?? 字符串长度为偶数时正确,长度为奇数时最后的字符变为问号 以 GBK 方式读取 UTF-8 编码的中文,然后又用 UTF-8 的格式再次读取
锟拷码 锟斤拷锟斤拷要锟矫猴拷学习锟斤拷锟斤拷锟斤拷 全中文字符,且大部分字符为“锟斤拷”这几个字符 以 UTF-8 方式读取 GBK 编码的中文,然后又用 GBK 的格式再次读取
烫烫烫 烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫烫 字符显示为“烫烫烫”这几个字符 VC Debug 模式下,栈内存未初始化
屯屯屯 屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯屯 字符显示为“屯屯屯”这几个字符 VC Debug 模式下,堆内存未初始化

避免乱码基本原则:使用 utf-8 代替 gbk/gb2312。

文件名乱码

安装 convmv,使用 convmv 命令转换编码格式。示例:

$ convmv -f GBK -t UTF-8 --notest --nosmart file

-f 指定原始编码,-t 指定输出编码。使用 convmv --list 可查询所有支持的编码。 --notest 表示非测试而是要进行转码(如果不使用该参数只会打印出转换结果而不会实际转码),--smart 表示如果已经是 UTF-8 则忽略。

文件内容乱码

使用 iconv 命令转换格式。示例:

$ iconv -f GBK -t UTF-8 -o new-file origin-file

-f 指定原始编码,-t 指定输出编码。使用 iconv -l 可查询所有支持的编码。-o 指定输出文件。

zip 压缩包乱码

问题描述

ZIP文件在不同平台压缩时,对于文件名会有不同的编码,主要分为下面两类:

  1. Windows平台,默认的中文编码为GBK,因此压缩后的文件名编码格式为GBK。
  2. Linux/MacOS平台,默认的中文编码为UTF8,因此压缩后的文件名编码格式为UTF8。

这样就存在一个问题,在Windows上压缩的文件放到MacOS上解压,或者将Windows上压缩的文件上传到服务器上解压后处理,里面的文件名都会出现乱码情况。出现这个问题,主要是因为ZIP标准公布于1989年1月,那时还没有Unicode标准。在当前ZIP标准中,Info-ZIP Unicode Path Extra Field(0x7075)会记录UTF8的编码名。

但是,这个字段不是强制字段,允许为空,Linux/Mac OS在压缩时都不会记录这个标识,因此,无法识别出zip包采用的编码方式,导致解压时会出现乱码。

方案

避免方法:非 utf8 编码环境下(一般 windows 下的中文环境即是)不使用 zip 进行压缩(建议使用 7z)。

解决方案:打补丁,如 Ubuntu 那样安装补丁 unzip-iconv,或使用较新的方案unzip-natspec;依云姐姐也提供了一个Python脚本解决方案 gbkunzip

补丁方案命令示例:

$ unzip -O gbk file.zip

file.zip 是压缩文件,gbk 是该文件的编码格式,以 -O 指定(原版 unzip 无 -O 选项)。

openSUSE 论坛坛友讨论提供的测试文件:4455.zip (785 KB)

openQA

大致的原理就是开一个虚拟机,然后模拟用户活动:https://openqa.opensuse.org

而且测试的项目也很多,除了安装,重启,安装桌面环境之类常规的测试。还有一些很特别的,比如说从 GNOME 桌面启动 Firefox,然后在关于界面一定会在某个坐标出现 Firefox 的 logo。打开 Dophin 然后右键菜单,新建文件的地方一定可以有那个文本文件。

另外还有两个项目也在使用来自 SUSE 的 openQA:

SDB

支持资料库。

Support Database (SDB) articles are written as solutions for technical problems with openSUSE.

给 pdf 电子书加目录

对许多人来说 pdf 格式的电子书最头疼的两件事:

  1. 每页都是没经过 OCR 处理过的图片
  2. 没有目录(ABBYY)

以下这个批量加目录的方法我用好久了,见过我这么操作过的都想学一下,这里详细地记录以下,也方便以后有人再问的时候 :)

用到的软件是 pdftk pdftk-java / pdftk-java · GitLab 。linux 发行版一般都有这个这个软件可以直接安装。

pdftk 的用法就是:输出 (dump_data) pdf 的元信息 (data.txt),编辑以后,重新倒入 (update_info) 到 pdf 文件里面

主要是这两条命令:

pdftk [my.pdf] dump_data > [data.txt]
pdftk [my.pdf] update_info [data.txt] output my2.pdf

在第一条命令输出的 data.txt 里面加入如下的内容,然后通过第二条命令就可以创建新的目录条目

BookmarkBegin
BookmarkTitle: name
BookmarkLevel: level
BookmarkPageNumber: page number

另外电子书的第一页通常是封面,紧接着的是其它的东西。但是书里面标注的页码的第一页往往后面的某页。

PDF 支持把页码标注成其它的格式 (page_labels),第一页标注成 cover,第二到第十页标注成罗马数字,然后从第十一页标注成 1,2,3,4,5,6…

# 把第一页标注成名字为 cover 的非数字 (NoNumber)
PageLabelBegin
PageLabelNewIndex: 1
PageLabelStart: 1
PageLabelPrefix: cover
PageLabelNumStyle: NoNumber

# 从第二页 (PageLabelNewIndex) 开始标注成小写罗马数字 (LowercaseRomanNumerals)
PageLabelBegin
PageLabelNewIndex: 2
PageLabelStart: 1 # 从数字 1 开始数,如果这里变成 3  => 起始的罗马数字会是 iii
PageLabelNumStyle: LowercaseRomanNumerals

# 从 {true start page} 开始用普通的数字标注
PageLabelBegin
PageLabelNewIndex: {true start page}
PageLabelStart: 1
PageLabelNumStyle: DecimalArabicNumerals

对于一本书,这种手动添加的方法会很慢,下面是一个小脚本来半自动化。

由于电子书 100% 可以搜索到这种格式的目录 编号 标题 页码。如果搜索不到,也可以直接从书里面复制。

复制粘贴一下,调整成这种格式

14
I: Reduction Semantics	1
	1 Semantics via Syntax	5
	2 Analyzing Syntactic Semantics	13
	3 The λ-Calculus	23
	4 ISWIM	45
II: PLT Redex	201
	11 The Basics	205
	12 Variables and Meta-functions	217
	13 Layered Development	227
	14 Testing	237
......

第一行是对于人类,而非 pdf 格式来说真正的第一页

后面根据行首 tab 的数量来决定目录的层级

每行后面的数字是页码

然后用这个小脚本 toc-gen.py

#!/usr/bin/env python3

#
# Usage
# toc-gen.py  < edited-toc.txt
#

def make_offset(off: int):
    if off > 1:
        print("""PageLabelBegin
PageLabelNewIndex: 1
PageLabelStart: 1
PageLabelPrefix: cover
PageLabelNumStyle: NoNumber""")

    if off > 2:
        print("""PageLabelBegin
PageLabelNewIndex: 2
PageLabelStart: 1
PageLabelNumStyle: LowercaseRomanNumerals""")

    print(f"""PageLabelBegin
PageLabelNewIndex: {off}
PageLabelStart: 1
PageLabelNumStyle: DecimalArabicNumerals""")


def make_bookmark(t: str, l: int, p: int):
    print(f"""BookmarkBegin
BookmarkTitle: {t}
BookmarkLevel: {l}
BookmarkPageNumber: {p}""")


if __name__ == '__main__':
    offset = int(input())
    make_offset(offset)
    while True:
        try:
            line = input()
            if not line.strip():
                break
        except EOFError:
            break

        title = " ".join(line.split()[0:-1])
        n_of_tabs = len(line) - len(line.lstrip())
        page = int(line.split()[-1])

        make_bookmark(t=title,
                      l=n_of_tabs + 1,
                      p=page + offset)

来获取这些内容,把这些内容粘贴到 [data.txt] 后面,然后再用 pdftk 的第二条命令

PageLabelBegin
PageLabelNewIndex: 1
PageLabelStart: 1
PageLabelPrefix: cover
PageLabelNumStyle: NoNumber
PageLabelBegin
PageLabelNewIndex: 2
PageLabelStart: 1
PageLabelNumStyle: LowercaseRomanNumerals
PageLabelBegin
PageLabelNewIndex: 14
PageLabelStart: 1
PageLabelNumStyle: DecimalArabicNumerals
BookmarkBegin
BookmarkTitle: Reduction Semantics
BookmarkLevel: 1
BookmarkPageNumber: 15
BookmarkBegin
BookmarkTitle: Semantics via Syntax
BookmarkLevel: 2
BookmarkPageNumber: 19
BookmarkBegin
BookmarkTitle: Analyzing Syntactic Semantics
BookmarkLevel: 2
BookmarkPageNumber: 27
BookmarkBegin
BookmarkTitle: The λ-Calculus
BookmarkLevel: 2
BookmarkPageNumber: 37
BookmarkBegin
BookmarkTitle: ISWIM
BookmarkLevel: 2
BookmarkPageNumber: 59
BookmarkBegin
BookmarkTitle: An Abstract Syntax Machine
BookmarkLevel: 2
BookmarkPageNumber: 79
BookmarkBegin
BookmarkTitle: Abstract Register Machines
BookmarkLevel: 2
BookmarkPageNumber: 103
BookmarkBegin
BookmarkTitle: Tail Calls and More Space Savings
BookmarkLevel: 2
BookmarkPageNumber: 121
BookmarkBegin
BookmarkTitle: Control: Errors, Exceptions, and Continuations
BookmarkLevel: 2
BookmarkPageNumber: 129
BookmarkBegin
BookmarkTitle: State: Imperative Assignment
..............

Bingo! 这下舒服了 :)

Recover root password

更个新,不能 sudo 了,安装的时候也没设置 root 密码,哎…(PS:就 Fedora 系操作不一样)

SDB:Recover root password

# mount -o rw /dev/sda1 /mnt
# mount -o bind /proc /mnt/proc
# mount -o bind /sys /mnt/sys
# mount -o bind /dev /mnt/dev
# chroot /mnt
# mount -a
# passwd
# exit
# reboot

Stream audio from your Android

pulseaudio 需安装 pulseaudio-module-bluetooth,pipewire 直接用。

我发现声音小,需要同时调整手机与电脑音量。

VLC Player 設定串流伺服器(Streaming Server)

Media => Stream…

PyPI 镜像

临时使用

$ pip install -i https://pypi.tuna.tsinghua.edu.cn/simple some-package

设为默认

$ pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
Writing to /home/kurome/.config/pip/pip.conf

快捷键

  • 在 Dolphin 文件浏览器中,直接使用 F4 即可调出命令行界面
  • 查看所有启动窗口程序 Ctrl + F10
  • 触控板文字的选择
    • 先在开头点一下, 此时不需要按住 shift, 到了结尾的时候按住 shift 再点一下就行了
    • 食指滑动到选择段开始,大拇指侧面按下去,然后食指滑动到选择段末尾,最后大拇指松开。
  • 触摸板手势
    • 单指点击:相当于单击鼠标左键。
    • 单指双击:相当于双击鼠标左键。
    • 单指移动:移动桌面上的光标。
    • 左键按压:相当于单击鼠标左键。
    • 右键按压:相当于单击鼠标右键。
    • 双指点击:相当于单击鼠标右键。
    • 双指上下滑动:滚动浏览屏幕或文档。

Questions

无法读取 exfat 、 .7z 和 .rar

$ sudo zypper in fuse-exfat exfat-utils
$ sudo zypper in p7zip-full
$ sudo zypper in unrar 

vscode keychain issues for KDE

$ sudo zypper in gnome-keyring

提示添加密码的时候为空就行了,否则每次启动 vscode 都需要输入一次密码。

Typora 字体问题

如果 Typora 字体如上面那样,每个字大小不一样:

  • 整个应用的语言设置为英语

  • 在 conf.user.json 指定字体

    {
      "defaultFontFamily": {
        "standard": "Source Han Sans CN", //String - Defaults to "Times New Roman".
        "serif": "Source Han Sans CN", // String - Defaults to "Times New Roman".
        "sansSerif": "Source Han Sans CN", // String - Defaults to "Arial".
        "monospace": "JetBrains Mono" // String - Defaults to "Courier New".
      }
    }
    
rm .Xauthority

nothing provides ‘libuuid’ needed by the to be installed xmind

BearChild, [7/21/22 10:14 PM] 强行装即可 libuuid 的依赖对于大多数 opensuse 安装来讲,都可以忽略,打包的问题

安装百度网盘的依赖问题

libuuid1、mozilla-nss,应对这种包的可能常用套路:直接搜索找不到明显可能相似的包,在忽视依赖关系安装之后 ldd 一下执行文件,通过对应 soname 去找对应包,有 soname 的话 zypper 应该是支持直接 in 找对应依赖的,如果 zypper 搞不定可以用隔壁的 dnf ,配置下源,然后直接 dnf in soname 就知道是谁提供的了(大佬用不用不知道,我是不用

High cpu usage of Goldendict

full-text search 在 openSUSE 中是默认开启的,Disable full-text search: Preferences => Full-text search

Set a different input method for each app window

System Settings => Input Devices => Keyboard => Layouts => Switching Policy => Application

安装软件碰到碰到冲突,应该如何选择解决方式?

出现这种情况大体可以有以下几个原则:

  1. 不要变更操作系统架构,比如把原来的 x86_64 变成 i586,(命令行执行 uname -m 可以让你知道你的系统架构,或者说 openSUSE 版本是 32 位还是 64 位),你也知道 32 位和 64 位不是一个东西。 1.1 这里有一个特例是 x86_64 -> noarch 这种,比如有些 python 的软件包是存在的。
  2. 能不卸载就不卸载。比如安装一个软件包让你卸载掉 700 多个软件包。
  3. 除非你知道你在做什么,比如我自己就是打包匠,我知道我的包可能 specfile 有一个地方写错了,否则不要用忽略依赖关系强制安装的选项。因为这么选了之后 YaST 再无可能查出故障。
  4. 变更软件包的厂商(制作人)的原则: 4.1 除非你知道你在做什么,否则官方源优于所有其它源。比如 xxx -> openSUSE 这种变更是允许的。某种程度上,在你不是很了解 openSUSE 包管理体系的时候它能够有效地无形中纠正你做出的一些错误选择。比如你切换了一个系统软件包到不稳定的版本,它能给改过来。但是如果你知道你在做什么就不必了,比如你通过 KDE:Current 把 KDE 升级为 4.13.2,而官方源中是 4.11,这种情况就不必降级。 4.2 除非你知道你在做什么,否则官方开发源优于除了官方源以外的所有其它源。比如 home:xxx -> devel:xxx 这种由 home 切换到非 home 的变更是允许的。因为 home 源谁都可以申请,软件包的质量参差不齐,开发源是官方认可的打包者为发行版开发软件包的地方,相对质量有所保证。但是如果你知道你在做什么就不必了,比如我可能知道 13.1 的 glew 有 bug,于是我会在我的 home 源里制作一个修复版本。这时肯定要安装我自己的。 4.3 只从 home 源中取自己需要的、且官方没有提供的软件包。比如我的 home 里可能有一个你需要的 hime 输入法,但同时也有一个非常老的 gtk2(会导致你后续基本上所有 gtk 相关的软件包都会弹出冲突解决对话框),你只装 hime 是不会带上我的 gtk 的,除非是你操作失误,选择切换系统软件包到该源。从图中看你肯定有这样的失误了。这是个一步错,步步都可能错的问题。
  5. 能不降级就不降级。比如 3.10 版本降级到 3.9 版本,这是没有必要的。

如果这 5 条军规之间产生冲突,编号越小的作用力越大。比如,开发源中的版本是 3.9, 而 home 源中的版本是 3.10,那么提示的时候,版本规律要服从软件源优先级规律,所以要选择把 3.10 版本降级为开发源中的 3.9。

Spotify: “Ding” notification for each played song

Hanjingxue, [9/29/22 8:17 AM] 你可以去 spotify flatpak 对应的 GitHub 仓库的 issue 列表看看有没有人遇到过相同的问题

BearChild, [9/29/22 8:17 AM] openSUSE 自己是不会给你“咚”的声音的

总结:除了使用 Google 外,还可以到 Github Issue 查找(而且优先级更高)。

具体就是关闭 Spotify 的 Settings => Display => show desktop notifications…

Teams flatpak doesn’t seem to use proxy

首先通过 env 查看是否设置了 proxy 相关的环境变量

如果设置了,那么运行

$ flatpak run --env=http_proxy=$http_proxy --env=HTTP_PROXY=$HTTP_PROXY --env=https_proxy=$https_proxy --env=HTTPS_PROXY=$HTTPS_proxy com.usebottles.bottles

如果起作用,则设置永久生效

$ flatpak override --user --env=http_proxy=$http_proxy --env=HTTP_PROXY=$HTTP_PROXY --env=https_proxy=$https_proxy --env=HTTPS_PROXY=$HTTPS_proxy com.usebottles.bottles

运行如下命令检查、还原覆盖的环境变量

$ flatpak override --show com.usebottles.bottles
$ flatpak override --reset com.usebottles.bottles

Since version 1.8.0 the Flatseal app supports modifying, displaying, and resetting global permissions.

Winedevice.exe is still running after killing wine processes

通过System Activity可能显示不全,用如下命令杀死所有 exe 进程:

$ kill -9 $(ps aux | grep -i '\.exe' | awk '{print $2}'| tr '\n' ' ')

audio: Unknown audio driver `pa'

Just install “qemu-audio-pa” and be done!

Dolphin 搜索不支持中文

这是因为 baloo 这个文件搜索的后端有不能搜索中文的 bug,一个回避的解决办法就是不用这个帯数据库的索引搜索,即取消勾选系统设置=>搜索=>文件搜索。

更新 .desktop 文件后 KDE Plasma 并随之不更新

问题描述:在更新 .desktop 文件的 Exec 部分后,运行 KDE Plasma 桌面上的快捷图标,会报错,因为其没有更新,是原先的路径与名称,重新登陆与重启都无法解决问题。

解决方法:当在终端直接运行该 GUI程序后,再次点击快捷图标会发现其已更新。

可能相关文章:Application launcher update after creating .desktop file

sudo update-desktop-database
update-desktop-database ~/.local/share/applications
kbuildsycoca5

Node.js

npm start use hostname instead of localhost on openSUSE

问题描述:我的问题与鹤仙人问题是相反的,我的 hostname 为 openSUSE, opensuse:3000 访问不了,直接 localhost:3000、127.0.0.1:3000 可以访问,即使 /etc/hosts 有 openSUSE 别名,问题出在 Clash,报错为

[WARN] [TCP] dial failed error=couldn't find ip: opensuse proxy=DIRECT rAddr=opensuse:3000 rule=DstPort rulePayload=3000

解决方法一:package.json:

{
  ...
  "scripts": {
    "start": "HOST=localhost react-scripts start",
    ...
  }
}

解决方法二:~/.profile

export HOST=localhost