General troubleshooting (简体中文) - ArchWiki

Jump to content

# General troubleshooting (简体中文)

From ArchWiki

相关文章

- Reporting bug guidelines (简体中文)
- Step-by-step debugging guide
- Debug - Getting Traces (简体中文)
- IRC Collaborative Debugging

翻译状态：本文是 General troubleshooting 的翻译。上次翻译日期：2018-04-02。如果英文版本有所更改，则您可以帮助同步翻译。

本文介绍了一些常规的故障排除方法。有关特定应用程序的问题，请参阅该特定程序的 wiki 页面。

## 常用手段

### 注意细节

为了解决遇到的问题，对当前使用的这个程序，你应该有一个基本的了解，这是 至关重要 的。它是如何工作的，它依赖什么才能正常运行？如果不能很好地回答这些问题，最好阅读一下这些出错程序的 Archwiki 文章。一旦你觉得你已经理解了它，你将更容易找出问题的原因。

### 常见问题 / 检查项

下面列出了许多常见问题，用于排查故障。在每个问题下都有注释，说明你该如何回答这个问题，紧接着的是一些如何收集数据的简单示例，还有查看各种日志的工具。

1. 出现了什么故障？
     请尽可能精确地描述问题，这将帮助你在查找特定信息的时候不至感到困惑或扯到别的方面去。
2. 是否显示了错误信息？（如果有的话）
     将包含相关 错误信息 的 完整输出 复制并粘贴到类似 `$HOME/issue.log` 这样单独的文件中。例如，可以将以下 mkinitcpio 命令的输出转发到 `$HOME/issue.log`：

         $ mkinitcpio -p linux >> $HOME/issue.log

3. 可以复现这个故障码？
     如果是这样，请 按步骤 给出 确切的 指示/命令来做到这一点。
4. 第一次遇到这些故障的时间，以及从没有故障到故障发生之间你修改了什么内容？
     如果这种情况发生在某次升级之后，可以列出 所有已升级的包。包括 版本号，同时粘贴 pacman.log (`/var/log/pacman.log`) 的升级日志。使用 systemd 的 systemctl 工具检查故障程序依赖的 所有 服务的运行状态。例如，可以将 systemd 命令的输出转发到 `$HOME/issue.log`：

         $ systemctl status dhcpcd@eth0.service >> $HOME/issue.log

     注意： 使用 `>>` 可以保证 `$HOME/issue.log` 中之前保存的内容不会被覆盖。

### 寻求解决

不要通过这样的表述来寻求问题的解决：

程序 X 不工作了。

描述整个系统的环境更有助于解决问题，比如：

应用程序 X 在执行 Z 任务时，会报出 Y 错误，条件是 A 和 B。

### 额外支援

利用你眼前的所有信息，你应该对系统里发生了什么有一个较好的认识，并且可以开始着手修复了。

如果需要额外支援，官方论坛 或 IRC （irc.freenode.net 上的 #archlinux 频道） 都可以提供帮助。更多频道可参考 IRC channels。

注意： 技术支持 仅限于 Arch Linux 而非 基于 Arch 的发行版。

当要求贴出 完整 的 输出 / 日志 时，不能仅仅贴出你认为的重要部分。信息来源应该包括：

- 所有涉及到的命令的完整输出，不要只选择你认为相关的东西。
- 来自 systemd 的 `journalctl` 的输出。要获取更多的输出，请使用 `systemd.log_level=debug` 引导参数。
- 日志文件（看一下 `/var/log` 目录）
- 相关的配置文件
- 相关的驱动程序
- 相关软件包的版本
- 内核相关：`dmesg`。对于启动问题，至少贴出最后 10 行，多贴一些当然更好。
- 网络相关：相关命令的完整输出，再加上所有相关配置文件。
- Xorg 相关： `/var/log/Xorg.0.log`，如果你已经覆盖了出问题的日志，就贴在这之前的日志。
- Pacman 相关：如果最近的更新弄坏了什么东西，请到 `/var/log/pacman.log` 找它。

贴出这些信息有一个更好的方式，就是使用在线剪贴板 (pastebin)。你可以 安装 pbpstAUR 或 gist 来自动上传信息。例如，要上传这次启动以来的 systemd 日志，可以这么做：

    # journalctl -xb | pbpst -S

这将返回一个链接，你可以把它贴到论坛或 IRC。

另外，在提问之前，请先阅读 提问的智慧 和 行为准则。

## 系统启动问题

诊断 启动过程 中的问题主要是修改 内核参数，然后重启系统。

如果系统无法启动，可以从 live 镜像 启动并 chroot 到现有系统。

### 控制台的输出信息

在启动过程完成以后，屏幕会被清空并显示登录提示符，这使得用户无法看到初始化过程中的输出和其中的错误信息。这一默认特性可以使用接下来几节中的方法进行修改。

请注意，无论选择下面哪个方法，在启动后通过使用 `dmesg` 或 `journalctl -b` 都可以显示内核消息，用于检查错误。

#### 输出流控制

以下是适用于大多数终端模拟器的基本操作，包括虚拟终端 (vc)：

- 按 `Ctrl+S` 暂停输出
- 按 `Ctrl+Q` 继续输出

这样不仅会暂停输出，而且会暂停尝试打印到终端的程序，即暂停输出时会阻塞 `write()` 调用。 如果你的 init 进程出现冻结，请确保系统控制台没有暂停。

要查看已经显示过的错误信息，参见 Getty (简体中文)#将引导消息保留在 tty1 上。

#### 回滚显示

回滚显示允许用户查看已经从控制台滚动过去并消失的文字内容。这通常是在视频适配器和显示设备之间创建缓冲（称为回滚缓冲区）实现的。默认情况下，将缓冲的内容上下滚动的快捷键是 `Shift+PageUp` 和 `Shift+PageDown`。

如果回滚内容没有完全包含足够的信息，可能需要扩大回滚缓冲区的大小来容纳更多输出。这可以通过配置内核的 framebuffer console（fbcon，帧缓冲控制台）来实现，修改 内核参数 `fbcon=scrollback:Nk` 即可，其中 `N` 是缓冲区大小，单位是 kB，默认是 32k。

如果这不奏效，你的 framebuffer console 可能没有正确地启用。参阅 Framebuffer Console documentation 来查找其他影响参数，比如修改帧缓冲驱动。

#### Debug 输出

在启动时，大部分来自内核的消息都是隐藏的，可以加入不同的内核参数来输出更多信息。最简单的是这些：

- `debug` 可以同时启用来自内核和 systemd 的调试信息
- `ignore_loglevel` 强制显示 所有 内核消息

在特定情况下有用的其他参数如下：

- `earlyprintk=vga,keep` 在早期启动过程中就输出内核消息，用于内核在有输出前就崩溃的情况下。在 EFI 系统上要把 `vga` 改成 `efi`。
- `log_buf_len=16M` 用于分配一个更大 (16MB) 的内核消息缓冲区，用来保证 debug 输出不被覆盖。

还有很多独立的调试参数，用于在特定的子系统中启用调试，例如 `bootmem_debug` 和 `sched_debug`。更多详细信息请参考 kernel parameter documentation。

注意： 如果无法回滚的足够远以查看所需的启动输出，你需要扩大 回滚缓冲区 的大小。

### 故障恢复控制台

在启动过程中的某个阶段获取一个交互式 shell 可以帮助你准确找出问题出在哪里，以及为何失败。有几个内核参数可以做到这一点，但它们都启动了一个正常的shell，可以随时 `exit` 让内核恢复正在执行的操作：

- `rescue` 在根文件系统刚刚被挂载为读写模式的时候启动一个 shell
- `emergency` 可以在更早的时候启动 shell，早于大部分文件系统挂载之前
- `init=/bin/sh`（作为最后的选择）把 init 程序改成 root shell。因为 `rescue` 和 `emergency` 都依赖于 systemd，而这可以在 systemd 坏掉的时候工作

还有一个选择，那就是 systemd 的 debug-shell，它在 `tty9` 上新增了一个 root shell，可以按 Ctrl+Alt+F9 来使用。这个功能可以通过在 内核参数 中添加 `systemd.debug-shell`，或者是 启用 `debug-shell.service` 来打开。注意在使用完后禁用该服务，避免在每次启动时都打开 root shell 而带来安全风险。

### Intel 显卡造成的黑屏

这很可能是 kernel mode setting 的问题造成的。尝试 disabling modesetting 或者修改 video port。

### 加载内核时卡住

尝试添加 `acpi=off` 内核参数来关闭 ACPI。

### 调试内核模块

参见 Kernel modules#Obtaining information。

### 调试硬件

- 按照 udev#Debug output 的说明可以显示额外硬件调试信息。
- 确保你的系统已经安装了 Microcode 更新。
- 使用 Memtest86+ 来测试设备的 RAM，不可靠的 RAM 可能会导致一些非常奇怪的问题，从随机崩溃到数据损坏都有可能。

## 内核崩溃（Kernel panic）

Linux 内核进入不可恢复的故障状态时，即发生了“内核崩溃” （kernel panic）。这种状态通常来源于错误的硬件驱动程序，导致内核死锁，无响应并需要重新启动。在死锁之前，会生成一条诊断消息，其中包括：发生崩溃时的机器状态，导致崩溃的内核函数的调用栈，以及当前加载的模块的列表。幸运的是，使用 mainline（主线）版本的内核（比如官方仓库提供的内核）不会经常发生内核崩溃，但是当它们发生时，你需要知道如何处理它们。

注意： Kernel panics 有时被称为 oops 或 Kernel oops，虽然 panics 和 oops 都是在出错的状态下才会发生，但是 oops 更为通用，因为它并不一定会导致内核死锁，有时内核可以通过结束出错的任务来恢复并继续运行。
提示： 在启动时传递参数 `oops=panic` 或者在 `/proc/sys/kernel/panic_on_oops` 中写入 `1` 来强制用 panic 代替可恢复的 oops。如果你认为自动恢复 oops 导致了小概率的系统不稳定，进而导致了后来的错误难以被诊断，那么建议你这样做。

### 查看 panic 信息

如果在早期启动过程中发生了 kernel panic，你或许会在控制台上看到包含 "Kernel panic - not syncing:" 的消息，一旦 Systemd 开始运行，内核消息就会被捕捉到并写入系统日志。但是，当 Kernel panic 发生时，内核发出的诊断信息 几乎不会 被写入硬盘上的日志文件，因为在 `system-journald` 运作前内核就死锁了。因此，检查内核崩溃消息的唯一方法是在崩溃时从控制台看错误信息（如果没有设置 kdump crashkernel 的话）。可以用以下内核参数来启动，这样就能重现 tty1 上的错误信息：

    systemd.journald.forward_to_console=1 console=tty1

提示： 如果崩溃信息滚动得太快导致无法阅读，可以在启动时尝试添加 `pause_on_oops=seconds` 内核参数。

#### 示例场景：模块损坏

根据诊断信息，我们可以大致推断出是哪个子系统或者模块导致了崩溃。在这个示例中，我们假设机器在启动时发生了 panic。注意那些用 粗体 标记的行：

    kernel: BUG: unable to handle kernel NULL pointer dereference at (null) [1]
    kernel: IP: fw_core_init+0x18/0x1000 [firewire_core] [2]
    kernel: PGD 718d00067
    kernel: P4D 718d00067
    kernel: PUD 7b3611067
    kernel: PMD 0
    kernel:
    kernel: Oops: 0002 [#1] PREEMPT SMP
    kernel: Modules linked in: firewire_core(+) crc_itu_t cfg80211 rfkill ipt_REJECT nf_reject_ipv4 nf_log_ipv4 nf_log_common xt_LOG nf_conntrack_ipv4 ... [3]
    kernel: CPU: 6 PID: 1438 Comm: modprobe Tainted: P           O    4.13.3-1-ARCH #1
    kernel: Hardware name: Gigabyte Technology Co., Ltd. H97-D3H/H97-D3H-CF, BIOS F5 06/26/2014
    kernel: task: ffff9c667abd9e00 task.stack: ffffb53b8db34000
    kernel: RIP: 0010:fw_core_init+0x18/0x1000 [firewire_core]
    kernel: RSP: 0018:ffffb53b8db37c68 EFLAGS: 00010246
    kernel: RAX: 0000000000000000 RBX: 0000000000000000 RCX: 0000000000000000
    kernel: RDX: 0000000000000000 RSI: 0000000000000008 RDI: ffffffffc16d3af4
    kernel: RBP: ffffb53b8db37c70 R08: 0000000000000000 R09: ffffffffae113e95
    kernel: R10: ffffe93edfdb9680 R11: 0000000000000000 R12: ffffffffc16d9000
    kernel: R13: ffff9c6729bf8f60 R14: ffffffffc16d5710 R15: ffff9c6736e55840
    kernel: FS:  00007f301fc80b80(0000) GS:ffff9c675dd80000(0000) knlGS:0000000000000000
    kernel: CS:  0010 DS: 0000 ES: 0000 CR0: 0000000080050033
    kernel: CR2: 0000000000000000 CR3: 00000007c6456000 CR4: 00000000001406e0
    kernel: Call Trace:
    kernel:  do_one_initcall+0x50/0x190 [4]
    kernel:  ? do_init_module+0x27/0x1f2
    kernel:  do_init_module+0x5f/0x1f2
    kernel:  load_module+0x23f3/0x2be0
    kernel:  SYSC_init_module+0x16b/0x1a0
    kernel:  ? SYSC_init_module+0x16b/0x1a0
    kernel:  SyS_init_module+0xe/0x10
    kernel:  entry_SYSCALL_64_fastpath+0x1a/0xa5
    kernel: RIP: 0033:0x7f301f3a2a0a
    kernel: RSP: 002b:00007ffcabbd1998 EFLAGS: 00000246 ORIG_RAX: 00000000000000af
    kernel: RAX: ffffffffffffffda RBX: 0000000000c85a48 RCX: 00007f301f3a2a0a
    kernel: RDX: 000000000041aada RSI: 000000000001a738 RDI: 00007f301e7eb010
    kernel: RBP: 0000000000c8a520 R08: 0000000000000001 R09: 0000000000000085
    kernel: R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000c79208
    kernel: R13: 0000000000c8b4d8 R14: 00007f301e7fffff R15: 0000000000000030
    kernel: Code: <c7> 04 25 00 00 00 00 01 00 00 00 bb f4 ff ff ff e8 73 43 9c ec 48
    kernel: RIP: fw_core_init+0x18/0x1000 [firewire_core] RSP: ffffb53b8db37c68
    kernel: CR2: 0000000000000000
    kernel: ---[ end trace 71f4306ea1238f17 ]---
    kernel: Kernel panic - not syncing: Fatal exception [5]
    kernel: Kernel Offset: 0x80000000 from 0xffffffff810000000 (relocation range: 0xffffffff800000000-0xfffffffffbffffffff
    kernel: ---[ end Kernel panic - not syncing: Fatal exception

- [1] 表明了导致 panic 的错误类型。此处表示一个程序 bug。
- [2] 表明 panic 发生在 firewire_core 模块中的 fw_core_init 函数中。
- [3] 表明 firewire_core 模块是最后一个要加载的模块。
- [4] 表明调用 fw_core_init 的函数是 do_one_initcall。
- [5] 表明这个 oops 消息事实上是一次 kernel panic 并且系统已经死锁。

我们可以猜测，panic 发生在模块 firewire_core 加载后的初始化例程中。（我们或许可以认为，由于程序错误，这台机器的火线 (IEEE 1394) 相关硬件与这一版本的驱动模块不兼容，并且需要等待下一个版本的驱动发布）与此同时，让机器运行起来的最简单方法，就是不要加载这个模块。我们可以通过以下两种方式之一来完成这个操作：

- 如果这个模块在加载 initramfs 时就会被加载，那就在重启时加上内核参数 `rd.blacklist=firewire_core`。
- 否则就用这个内核参数重启 `module_blacklist=firewire_core`。

### 重启至 root shell 并修复故障

为了更改系统设置使得 panic 不再发生，你需要一个 root shell。如果 panic 发生在启动时，有几种方法可以在内核死锁前获得一个 root shell：

- 使用内核参数 `emergency`、`rd.emergency` 或 `-b` 重启电脑，这样可以在根文件系统挂载且 `systemd` 启动后就收到登录提示符。

  注意： 此时，根文件系统将会以只读方式挂载。执行 `# mount -o remount,rw /` 来改变这一设置。

- 使用内核参数 `rescue`、`rd.rescue`、`single`、`s`、`S` 或 `1` 在本地文件系统挂载完成后就得到登录提示符。
- 使用内核参数 `systemd.debug-shell=1` 在 tty9 上获得一个早期 root shell，然后按 `Ctrl-Alt-F9` 切换到它。
- 通过使用不同的内核参数重新引导来尝试禁用导致 panic 的内核功能。尝试“备用参数” `acpi=off` 和 `nolapic`。

  提示： 参阅 Linux 内核源码树中的 `Documentation/admin-guide/kernel-parameters.txt` 文件来查找所有内核参数。

- 作为最后的手段，你还可以使用 Arch Linux Installation CD 启动电脑，把根文件系统挂载到 `/mnt`，然后运行 `# arch-chroot /mnt`。

禁用导致 panic 的服务或程序，回滚有故障的更新或修复配置问题。

## 软件包管理

参阅适用于一般主题的 Pacman#Troubleshooting，以及适用于 PGP 密钥问题的 pacman/Package signing#Troubleshooting。

## fuser

This article or section needs expansion.

Reason: 需要更多关于其用法的信息 (Discuss in Talk:General troubleshooting (简体中文))

fuser 是一个用于识别进程占用的资源（如打开的文件、文件系统和 TCP/UDP 端口）的命令行工具。

fuser 由软件包 psmisc 提供，已经由 base 组安装。更多信息请查看 fuser(1)。

## 会话权限

注意： 你必须使用 systemd 作为你的 init 进程，本地会话才能正常工作。[1] 它是各种设备的 polkit 权限和 ACL 所必需的 （参见 `/usr/lib/udev/rules.d/70-uaccess.rules` 和 [2]）

首先，确保你有一个带 X 的可用本地会话：

    $ loginctl show-session $XDG_SESSION_ID

在输出中需要带有 `Remote=no` and `Active=yes` 字样。如果没有，确保 X 运行在和登录时一样的 tty 里面。这是保留登录会话所必须的。

基本 polkit 操作不需要额外的配置。但有一些 polkit 操作需要请求额外的身份认证，即使是本地会话也是如此。为了达成这项工作，必须运行一个 polkit 身份认证组件。更多信息可参见 polkit (简体中文)#身份认证组件。

## 错误信息： "error while loading shared libraries"

The factual accuracy of this article or section is disputed.

Reason: 在 soname bump 之后相关程序可能需要重新编译。 (Discuss in Talk:General troubleshooting (简体中文))

如果在运行程序时遇到类似于这样的错误：

    error while loading shared libraries: libusb-0.1.so.4: cannot open shared object file: No such file or directory

使用 pacman 或 pkgfile 来查找包含丢失共享库的软件包：

    $ pacman -Fs libusb-0.1.so.4

    extra/libusb-compat 0.1.5-1
        usr/lib/libusb-0.1.so.4

在上述例子中，需要 安装 软件包 libusb-compat。

这个错误也有可能意味着你用来安装这个软件的 PKGBUILD 里没有将这个共享库作为它的依赖库：如果来自官方源，请 报告一个 bug；如果来自 AUR，请在 AUR 网站相关页面上把它报告给维护者。

## 错误信息： "file: could not find any magic files!"

如果看到这条消息，则可能表示软件包更新破坏了动态链接程序的运行时依赖文件，并且系统现在已经基本瘫痪。在修复之前，你将无法重新编译或重新安装软件包或重建 initramfs。

### 错误原因

某次软件更新可能在 `/etc/ld.so.conf.d` 目录中添加了非法的 `filename.conf` 文件，或是错误地编辑了 `/etc/ld.so.conf` 文件。其后果就是动态链接程序的运行时依赖文件 `/etc/ld.so.cache` 使用了错误的数据重新生成了。这可能导致系统中所有依赖共享库的程序都出错（即几乎所有程序出错）。

### 解决方法

1. 使用 Arch Linux Installation CD 启动。
2. 挂载根文件系统 `/` 到 `/mnt`，挂载 `/boot` 文件系统到 `/mnt/boot`，然后用命令 `# arch-chroot /mnt` 切换到受损的系统中。
3. 检查 `/etc/ld.so.conf` 文件，删除所有不正确的内容。
4. 检查放在 `/etc/ld.so.conf.d/` 目录里的文件，删除所有不正确的文件。
5. 使用命令 `# ldconfig` 重新生成动态链接程序的运行时依赖文件 `/etc/ld.so.cache`。
6. 使用命令 `# mkinitcpio -p linux` 重新生成 Initramfs。
7. 退出 chroot 环境，卸载文件系统，然后重启到原来的系统中。

## 参阅

- Fix the Most Common Problems
- A how-to in troubleshooting for newcomers
- List of Tools for UBCD - Memtest-like tools to add to grub.cfg on UltimateBootCD.com
- Wikipedia:BIOS Boot partition
- REISUB
- Debug Logging to a Serial Console on Freedesktop.org
- How to Isolate Linux ACPI Issues on Archive.org

Categories:

- System administration (简体中文)
- System recovery (简体中文)
- Installation process (简体中文)

Hidden categories:

- Pages or sections flagged with Template:Expansion
- Pages or sections flagged with Template:Accuracy