分类

分类: linux

查看动态库的依赖关系树

今天调试一个内存泄露的问题, 表现是在 amd64 的机器上进程正常退出, 而 arm64 上会出现 指针错误.

$ ./lithium https://bing.com
[1223/105725.272479:INFO:command_line_ipc_client.cpp(58)] args item: ./lithium
[1223/105725.272716:INFO:command_line_ipc_client.cpp(58)] args item: --disable-gpu
[1223/105725.272742:INFO:command_line_ipc_client.cpp(58)] args item: --enable-print-preview
[1223/105725.272787:INFO:command_line_ipc_client.cpp(58)] args item: https://bing.com
[1223/105725.272809:INFO:command_line_ipc_client.cpp(58)] args item:
Found existing runtime, exit now!
*** Error in `./lithium': free(): invalid pointer: 0x00000000402c2f30 ***

这里, 先用 gdb 追踪了一下, 发现在 main() 函数退出后, 执行全局对象的 dtor() 时出了问题. 单步执行来追查, 发现是 protobuf 库在析构时挂了.

之后, 又使用 valgrind 来确认, 同样定位到了相同的问题点:

阅读全文 "查看动态库的依赖关系树" »

netstat 常用命令

netstat 作为调试网络问题的必备工具, 有些常用选项, 在这里记录一下.

  1. 显示路由表: netstat -r
  2. 显示所有连接: netstat -a
  3. 显示所有 TCP 连接: netstat -at
  4. 显示所有 UDP 连接: netstat -au
  5. 显示所有的 TCP 监听服务: netstat -lt
  6. 列举网络接口: netstat -ie
  7. 最常用选项: netstat -plent 显示本地 TCP 监听服务及其对应的进程信息
阅读全文 "netstat 常用命令" »

重新编译 linux 内核,开启 btf

默认的 archlinux 内核包并不包含对 BTF(BPF Type Format) 的支持,需要我们手动开启,

目前的内核版本是 5.6.4,我们使用 yaourt 来安装。

首先是安装 pahole 这个依赖包:

yaourt -S pahole

目前的 pahole 版本要依赖 libebl 库,而这个库并不是必需的,可以给它创建一个 软链接指向 libelf.so 即可。

阅读全文 "重新编译 linux 内核,开启 btf" »

下载 deb 安装包及其依赖包

这两天要为离线的 arm 服务器安装几个 deb 包,因为这些包都有许多上游的依赖包,得 一起把它们下载到本地。

这里以 ubuntu 18.04 (bionic) 为例,下载 arm64 架构的几个包。

首先就是配置安装源,因为本地环境不是 ubuntu,需要先搞一个 ubuntu 的环境,可以 考虑使用 docker 或者 debootstrap。这里选择使用后者,操作起来要更简单。

配置 ubuntu 18.04 amd64 环境

sudo debootstrap bionic rootfs http://mirrors.aliyun.com/ubuntu

这里用的是阿里云的安装源,系统目录位于 rootfs

阅读全文 "下载 deb 安装包及其依赖包" »

ssh 端口转发

有时需要临时在本地访问一下服务器上的未公开访问权限的服务,可以用 ssh 将此服务的 端口重映射到本地。使用起来也很简单,比如之前常用的 X11Forward 类似实现的。

下面以访问服务器的 127.0.0.1:8080 web 服务为例说明:

ssh -p 22 -v -N -L 0.0.0.0:8080:127.0.0.1:8080 user@example.com

以上命令即可将服务器上 8080 端口的服务映射到本地网络。其中各个参数的意义是:

  • -p 22 为服务器上的 sshd 服务的端口号,默认是22,可以略去这个选项
  • -v 交互式模式,会打印一些日志到终端里;可以略去
  • -N 表示不在服务器端执行命令,这样就不会打开服务器上的远程终端;可以略去
  • -L 0.0.0.0:8080:127.0.0.1:8080 将服务器上的 8080 映射到本地的 8080 端口
  • user@example.comssh 服务的用户名及服务器地址

之后就可以在本机浏览器里面访问 http://127.0.0.1:8080 地址了。

阅读全文 "ssh 端口转发" »

运行 gitk 时提示缺少 wish 命令

gitk 命令可以方便地查看 git 仓库中某个文件的更改历史。

但是 archlinux 平台上运行这个命令时却提示如下错误:

/usr/sbin/gitk: line 3: exec: wish: not found

查了一下, 发现是没有安装 tk 工具包,手动安装它即可:

sudo pacman -S tk

这个问题蛮早就有人反馈给上游了,目前还没有把它加到包依赖列表里。

阅读全文 "运行 gitk 时提示缺少 wish 命令" »

chroot 时做了什么

debian 社区,大都使用 chroot 环境做一些干净的编译打包操作,之前手动安装 debian 和 archlinux 系统时,也有在使用 chroot。但并不了解 chroot 时,系统究竟发生了什么。 在 2019 年最后一天,找时间看了下内核代码,才了解到里面的操作。

先说结论:chroot 改变当前进程所在的内核空间的一个叫做 current->root 的全局变量, 之后该进程所有的文件系统操作的路径,都以新的 path 作为根目录。

首先看 fs/open.c 中实现的 ksys_chroot() 系统调用:

阅读全文 "chroot 时做了什么" »

通过 USB 2 TTL 串口线连接树莓派4

刚好手边有 USB转 TTL 的串口线,不需要再通过 ssh 连接树莓派了。

首先就是串口线的接法,大致如下图:

USB_5V  <--> PI4外侧串口第一个口(5V)
USB_GND <--> PI4外侧串口第三个口(GND)
USB_RX <--> PI4外侧串口第四个口(GPIO14)
USB_TX <--> PI4外侧串口第五个口(GPIO15)

接好线之后,给树莓派供电,此时在电脑里面查看一下是否有串口设备:

$ ls /dev/ttyUSB*

这里有找到 /dev/ttyUSB0 设备。

使用 lsusb 命令查看一下:

Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 003 Device 002: ID 1358:c123 Realtek  Bluetooth Radio
Bus 003 Device 006: ID 1a86:7523 QinHeng Electronics HL-340 USB-Serial adapter
Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 002 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub
Bus 001 Device 003: ID 05e3:0610 Genesys Logic, Inc. 4-port hub
Bus 001 Device 002: ID 0a12:0001 Cambridge Silicon Radio, Ltd Bluetooth Dongle (HCI mode)
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub

这里显示的 HL-340 USB-Serial adapter 就是我们的 USB 串口连接器。 也可以在 `dmesg` 里面找到内核打印信息。

在电脑上安装串口工具,常用的是 minicom

$ sudo apt install minicom
阅读全文 "通过 USB 2 TTL 串口线连接树莓派4" »

pi4 配置无线网连接

手边没有可用的显示器,在配置树莓派 4 的时候,只能选择使用 headless 模式了。 但配置也比较简单,分以下几步。

将包含 pi4 raspbian 系统的 TF 卡连接到电脑上,有两个可用的分区,只需要在 boot 分区中操作。

首先创建一个空白的名为 ssh 的文件,用于开启 ssh 服务。

其次在 boot 分区创建 wpa_supplicant.conf 文件,用于设置无线网络连接信息,示例如下:

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=CN

network={
 ssid="YOUR_SSID"
 psk="SSID_PASSWORD"
}
阅读全文 "pi4 配置无线网连接" »

Linux 系统代理设置

目前 linux 终端里经常要下载一些东西, 比如:

  • git clone 一些内部的项目代码
  • go dep 下载一些第三方模块
  • depot_tools 下载谷歌官方的项目
  • cargo 更新包依赖

这些情况, 有部分网站是无法直连的, 还有一些即使边得上, 速度也很差. 针对这些应用, 我们可以设置一下终端里的代理环境, 使用 VPS 上布署的 中转服务器加速请求.

阅读全文 "Linux 系统代理设置" »

使用 multiarch 运行其它架构的程序

Debian 提供的 multiarch 功能对于调试跨架构的应用来说非常方便. 尽管 multiarch 常用于在 x86_64 的系统里面运行 x86 的程序.

以下操作以在 x86_64 的系统里面编译并运行 arm64 的应用为示例来演示一下 multiarch.

安装交叉编译的工具链

apt 仓库里面提供了多个架构的 gcc 工具链, 如果编译 arm64 平台的, 可以安装:

$ sudo apt install gcc-aarch64-linux-gnu

该工具包提供了包括编译器和链接器等:

/usr/bin/aarch64-linux-gnu-gcc
/usr/bin/aarch64-linux-gnu-gcc-ar
/usr/bin/aarch64-linux-gnu-gcc-nm
/usr/bin/aarch64-linux-gnu-gcc-ranlib
/usr/bin/aarch64-linux-gnu-gcov
/usr/bin/aarch64-linux-gnu-gcov-dump
/usr/bin/aarch64-linux-gnu-gcov-tool
阅读全文 "使用 multiarch 运行其它架构的程序" »

降级 Debian 系统

之前 NAS 服务器用的是 unstable 版的 debian 系统, 最近系统频繁更新, 比较麻烦, 正好 debian 10 - buster 也发正式版了, 就想着换成这个版本.

但是现在服务器上面跑着好几个服务, 不打算重新装系统, 就尝试着把 unstable 版本 降级为 buster 这个 stable 版.

更改 apt 源

之前的源列表是:

deb http://mirrors.ustc.edu.cn/debian sid main contrib non-free
deb-src http://mirrors.ustc.edu.cn/debian sid main contrib non-free

deb http://mirrors.huaweicloud.com/debian sid main contrib non-free
deb-src http://mirrors.huaweicloud.com/debian sid main contrib non-free
阅读全文 "降级 Debian 系统" »

常用的 Debian 源

这些年陆陆续续用了不少的 debian 仓库源. 印象中速度比较快的有这些:

  • http://ftp2.cn.debian.org/debian/, 指向的是清华大学源
  • http://ftp.cn.debian.org/debian/, 指向的是中科大源, 最终地址是: http://mirrors.ustc.edu.cn/debian/
  • http://mirrors.aliyun.com/debian/, 只有 i386/amd64 的
  • http://ftp.hk.debian.org/debian/, 服务器位于香港
  • https://mirrors.huaweicloud.com/debian/, 华为云提供的源
阅读全文 "常用的 Debian 源" »

systemd-networkd 启用 DHCP

在 Virtualbox 虚拟机中安装了不带图形界面的 debian 系统之后, 为了方便与宿主系统 间的通信, 就为它分配了两张虚拟网卡, 并把其中一张网卡的模式设置为了 Host-Only. 这样就可以与宿主系统共享同一个网段. 但是, 虚拟机中的 debian 系统默认只有在安装 时会扫描一下 DHCP, 系统运行起来以后, 需要手动处理, 比较麻烦.

现在, 可以使用 systemd-networkd 服务来自动配置这些网卡.

阅读全文 "systemd-networkd 启用 DHCP " »

Memory Mapping

mmap() 在进程的虚拟地址空间(virtual address space) 创建新的内存映射.

  • 文件映射, 将文件直接映射到进程虚拟内存, 内存页自动从文件中按需载入. 又被称作 file-based mapping 或 memory-mapped file.
  • 匿名映射, 不需要映射相应的文件, 而是把映射的内存页里的内容初始化为0.

进程之间共享内存映射:

  • 两个进程同时映射文件中的同一个区域时, 它们共享物理内存中相同的页面.
  • fork() 出来的子进程, 会持有父进程内存映射的复制, 它们指向同一个区域的物理内存.
阅读全文 "Memory Mapping" »

虚拟内存相关的操作

内存保护, mprotect()

mprotect() 改变一定范围内的虚拟内存页的保护方式.

锁定内存 mlock(), mlockall()

因为内核可能会将进程的内存页写到交换分区上, 如果该内存页上有敏感数据的话, 可能 导致它被泄露, 可以给关键的内存区域加锁, 告诉内核不要把这个区域的内存页执行交换 页的操作.

阅读全文 "虚拟内存相关的操作" »

文件锁

锁定文件的两个接口:

  • flock(), 用来锁定整个文件
  • fcntl(), 用来锁定文件的区域

基本用法是:

  • 给文件加锁
  • 一般的文件读写操作
  • 释放之前的锁
阅读全文 "文件锁" »

内核简介

可重入 (Reentrant Kernel)

多个进程可以在内核里同时执行. 当一个进程被挂起时, 它的所有运行状态都被保存下来, 在下次被恢复执行时, 就从之前的状态继续执行.

当一个函数只修改本地的变量时, 它是一个可重入的函数. 当内核里的函数不可重入时, 就得用锁机制, 来保证同时只有一个进程来调用这个不可 重入的函数.

阅读全文 "内核简介" »

Linux 桌面里打开 heic 格式的图片

iOS 11 之后, 就把默认的照片格式换成了 heic, 这个比较新的格式, 在其它平台上有 很大的兼容性问题, 到目前为止只有很少的图片查看工具支持它.

但这种情况正在得到改善, 比如前不久发布的 GIMP 2.10 已经支持对 heic 文件进行打开, 编辑以及保存了. ImageMagick 新版本也支持了这种 格式. 它们都使用了 libheif 这个库.

阅读全文 "Linux 桌面里打开 heic 格式的图片" »

录制终端

刚刚有个需求, 需要录制终端操作, 然后在别的机器上重放一下, 用于演示, 直接的做法 是启动 recordmydesktop 这样的屏幕录制工具, 生成 ogv 视频文件.

后来找了一下, 发现 bsdutils 这个包里带了 scriptreplay, 用于终端演示的, 使用方法 也很简单.

阅读全文 "录制终端" »

为何一直使用 Debian 发行版

陆陆续续有朋友向我推荐 Linux 桌面其它发行版, 比如 ArchLinux 这样的, 但我一直 没有切换过去. 首先一点, 这些发行版之前都有使用过, 包括 Debian GNU/Linux 在内, 它们都有各自的优势与不足, 但其中 Debian 这个发行版, 可以最大程度上满足我的需要, 现在大致列举一下吧.

阅读全文 "为何一直使用 Debian 发行版" »

cgroups

cgroup 功能

  • 限制资源容量, 包括 CPU, 内存, 网络, 文件系统等
  • 对资源访问的优先级, 比如 CPU, 或者 硬盘I/O
  • 资源计量, 比如, 服务商可以根据用户使用内存的多少来收费
  • 控制进程组, 比如挂起, 重启
阅读全文 "cgroups" »

Openbox 桌面环境里调整屏幕亮度

最近换到 openbox 了, 因为要编译程序, 其它桌面环境太占资源.

到了晚上, 笔记本屏幕太亮, 需要调整一下, 可以使用 gnome-settings-daemon 这个 软件包提供的 gsd-backlight-helper 来实现, 它其实是修改了 /sys/class/backlight/xxx_backlight/brightness 这个内核文件里的值. 直接手动 修改的话, 需要 root 权限, 但是可以使用 pkexec 命令来绕过, 因为 gnome-settings-daemon 已经注册了安全策略.

阅读全文 "Openbox 桌面环境里调整屏幕亮度" »

配置一下 tmux 窗口操作快捷键

最近换到了 tmux, 发现它默认的快捷键很难使用. 默认的快捷键前缀是 Ctrl+b, 要同时 用左手的小指和大拇指来按这两个键, 手指很酸痛, 对小指的压迫感太强. 我把它改为了 Ctrl+a.

而且, 默认的水平及竖直方向上的分屏快捷键是 %", 这两个字符跟分屏完全没有 关联系, 为了跟 vim 以及 Gnome 保持一致, 把这俩快捷键换成了 hv.

阅读全文 "配置一下 tmux 窗口操作快捷键" »

Linux 桌面成不了大器

今天发布了云音乐 1.1 版, 并不开心. 这些天被这一堆的桌面问题 坑得无语. 分两部分说吧.

差得不能再差的包管理工具

嗯, 同一个发行版, 不同的系统版本, 包名竟然不一样. 而且, Debian/deb 系的, 尤其喜欢拆包, 一个好好的软件包, 拆成一堆的小包, 一个 VLC 播放器, 被拆成了 十几个包. 更可恶的, Ubuntu 16.04 与 Ubuntu 17.10 上面, VLC 的解码器 被放到了不同的包里, 前者是 vlc-nox, 后者有 vlc-plugin-base, 但是还得 安装 vlc-bin. 这是自找没趣, 闲得没事儿干. 他们拆包时, 并没有为这个软件包 加入什么新的功能, 反而把一些包改得没了样子.

阅读全文 "Linux 桌面成不了大器" »

体验 Gnome 3.26

Gnome 的最新正式版 3.26 已经发布有一段时间了, 但是 Debian unstable 仓库里面只是在最近几天才把大部分 Gnome 组件从 3.24 升级到了 3.26.

使用 Gnome 桌面环境已经有近十年时间了, 从 Ubuntu 07.04, 07.10 开始, 接触到的就是 Gnome. 期间更换了多个桌面环境, 用起来最顺手最高效的, 还是 Gnome 桌面. 当时, 由于某些时期, Gnome 更新后无法正常启动, 或者因为 内存泄露的问题, 会偶尔切换到 openbox + fbpanel 的轻量环境.

阅读全文 "体验 Gnome 3.26" »

配置 HP Gen8 (4) UPS 自动关机

为了保障硬盘的安全, 之前为 Gen8 服务器安装了 APC UPS, 型号是 BK650-CH, 这个性价比挺高的, 断电时足够支持 Gen8 服务器正常运行十分钟. 但是, 当电池电量用完时, 服务器的电源仍然会被强制 切断, 并不能有效地保护硬盘. 为此, 这里使用 APC 提供的电源管理服务, 当市电中断, UPS 供电 一分钟后, 就自动关闭 Gen8 服务器.

BK650-CH 提供了 RJ45转 USB口的数据线, 将 RJ45端 插到 UPS 侧面的管理接口, USB端插到 Gen8 背面的 USB 接口.

阅读全文 "配置 HP Gen8 (4) UPS 自动关机" »

配置 HP Gen8 启动光盘位的系统

接上文, 当服务器中的四个硬盘位都安放了硬盘后, 在 BIOS 中关闭 HP Array RAID, 并开启 AHCI 模式. 这时, BIOS 就会优先尝试从 SATA1 启动, 因为我们已经把 SATA1~SATA4 组成了 ZFS RAID6, 上面并没有可用的引导器, 而 SATA5 上面的系统以及引导器, 并没有被服务器使用, 为此, 临时的解决方法是使用 U 盘引导 SATA5 上面的系统, 具体做法如下:

首先, 为 U 盘新建一个小的空白分区, 用于安装 GRUB:

$ sudo parted /dev/sdX mklabel msdos
$ sudo parted /dev/sdX mkpart primary fat32 1M 100M
$ sudo mkfs.fat -F32 /dev/sdX1
阅读全文 "配置 HP Gen8 启动光盘位的系统" »

配置 HP Gen8 启用 ZFS 文件系统

安装磁盘阵列, 并配置 ZFS raid6

当 debian 系统正常被安装到 SSD 之后, 把它从台式机上面卸下来, 然后安装到 Gen8 服务器的光驱位置. 当然, 这个需要先把 Gen8 的外壳打开, 在服务器的后面, 有两个 蓝色的旋扭, 把它们拧开之后, 稍微用力向后拉服务器的外壳, 应该就可以顺利把它打开了.

连接 SSD 的 SATA 接口是要接到主板上预留的一个 SATA 接口, 电源线要接到服务器 顶部的有四个接口的电源输出线上.

之后用 VGA 线缆连接 Gen8 服务器和显示器.

通电, 等主板自检完成之后, 按 F9 进入 BIOS 设置. 我们要关闭服务器自带的 RAID Controller, 把硬盘模式从 Array 改为 AHCI 模式. 然后修改启动顺序, 把硬盘启动放到第一个. 然后退出, 按 F10 保存设置.

机器重启后, 应该就可以正常读取 SSD 上面的 GRUB 了. 使用刚刚创建的用户登录 系统.

阅读全文 "配置 HP Gen8 启用 ZFS 文件系统" »

配置 HP Gen8 安装 debian 系统

安装 debian 系统

先把新的 120GB 的因特尔 SSD 挂到已有的 debian 系统上面, 这块 SSD 只用来放置 debian 系统, 所有的应用数据和用户文件都要放到 ZFS 文件系统上面.

分区

使用 parted 为它分区:

$ sudo parted /dev/sdb mklabel msdos
$ sudo parted /dev/sdb mkpart primary ext4 1MiB 100%
$ sudo mkfs.ext4 -F -L "Gen8" /dev/sdb1

这里要注意的是, Gen8 默认不支持 UEFI 启动, 所以为新的 SSD 创建 MSDOS 分区表. 并且创建一个 ext4 分区.

阅读全文 "配置 HP Gen8 安装 debian 系统" »