为什么 dmesg 在取消挂起时会响起终端铃声?

为什么 dmesg 在取消挂起时会响起终端铃声?

每当我取消挂起笔记本电脑时,我打开(正在运行)的 tmux 窗口dmesg -w就会亮起:

tmux 状态行的图像,其中一个窗口突出显示

从 tmux 手册页来看,这意味着窗口中运行的应用程序已经敲响了终端铃声。

我有另一台机器,其设置基本相同(相同的操作系统,相同的 tmux 配置),但这种情况不会发生——仅在这台特定的笔记本电脑上发生。为什么 dmesg 在这台机器上取消挂起时会响起终端铃声?

软件版本:

$ uname -a
Linux localhost 3.10.18 #1 SMP Mon Jan 8 23:08:08 PST 2018 armv7l armv7l armv7l GNU/Linux
$ lsb_release -cr
Release:        16.04
Codename:       xenial
$ tmux -V
tmux 2.6
$ dmesg --version
dmesg from util-linux 2.27.1

答案1

如果你检查 dmesg 的输出,你可以通过 grep 查找 ASCII BEL 字符来准确地看到它何时敲响铃声\a

$ dmesg | grep -C1 $'\a'
[    5.706427] usb 1-2: Manufacturer: HD WebCam
[    5.706434] usb 1-2: SerialNumber: NC2141103Q533020AALM03
[    5.798439] Unsafe core_pattern used with suid_dumpable=2. Pipe handler or fully qualified core dump path required.
--
[13843.531106] usb 1-2: Manufacturer: HD WebCam
[13843.531115] usb 1-2: SerialNumber: NC2141103Q533020AALM03
[13843.546586] uvcvideo: Found UVC 1.00 device HD WebCam (0bda:57cf)

有趣的是,铃声似乎是在初始化网络摄像头的过程中发生的。我们可以通过 od 管道来准确检查 BEL 正在打印的行中的位置:

$ dmesg | grep $'\a' | head -n 1 | od -c
0000000   [                   5   .   7   0   6   4   3   4   ]       u
0000020   s   b       1   -   2   :       S   e   r   i   a   l   N   u
0000040   m   b   e   r   :      \a   N   C   2   1   4   1   1   0   3
0000060   Q   5   3   3   0   2   0   A   A   L   M   0   3  \n
0000076

BEL 在此表示为\a,并且它打印在序列号 ( SerialNumber: ␇NC214...) 之前。 dmesg 似乎不太可能在一行的中间插入一个 BEL,所以也许是内核在记录它。

我们来检查一下源代码。也许 USB 驱动程序在记录序列号时正在打印铃声。我们可以用活格列普快速搜索Linux 4.12源码,发现相关文件很可能是drivers/usb/core/hub.c.然后,我们可以使用以下命令返回 Linux 3.10.18 源代码灵丹妙药,并找到相关函数:

static void announce_device(struct usb_device *udev)
{
    dev_info(&udev->dev, "New USB device found, idVendor=%04x, idProduct=%04x\n",
        le16_to_cpu(udev->descriptor.idVendor),
        le16_to_cpu(udev->descriptor.idProduct));
    dev_info(&udev->dev,
        "New USB device strings: Mfr=%d, Product=%d, SerialNumber=%d\n",
        udev->descriptor.iManufacturer,
        udev->descriptor.iProduct,
        udev->descriptor.iSerialNumber);
    show_string(udev, "Product", udev->product);
    show_string(udev, "Manufacturer", udev->manufacturer);
    show_string(udev, "SerialNumber", udev->serial);
}

show_string是一个非常简单的函数,定义在上面announce_device,几乎只是打印用冒号和空格分隔的参数:

static void show_string(struct usb_device *udev, char *id, char *string)
{
    if (!string)
        return;
    dev_info(&udev->dev, "%s: %s\n", id, string);
}

所以添加铃声的也不是内核。

USB 设备的序列号是多少?

我们可以使用 lsusb 检查:

$ lsusb -vd 0bda:57cf | grep iSerial
  iSerial                 2 NC2141103Q533020AALM03

好的,现在让我们通过 od 进行管道传输:

$ lsusb -vd 0bda:57cf | grep iSerial | od -c
0000000           i   S   e   r   i   a   l
0000020                                           2      \a   N   C   2
0000040   1   4   1   1   0   3   Q   5   3   3   0   2   0   A   A   L
0000060   M   0   3  \n
0000064

这表明网络摄像头的序列号实际上包含 ASCII BEL。

相关内容