[译]UUID和Linux:你需要知道的一切

本文为 UUIDs and Linux: Everything you ever need to know Update 的翻译。

UUID在Linux中为何如此特别?我[指原作者,下同]不知道!但是这儿有你需要知道的、关于UUID在Linux下的一切!

背景

UUID是128位长的数字,表示为32位的16进制数字,被用于在软件开发中、在没有上下文的情况下唯一地标识信息。RFC 4122描述了UUID的规范,一个UUID的例子是:

13152fae-d25a-4d78-b318-74397eb08184

UUID在Linux最熟悉的场景应该是块设备的标识符了吧。Windows世界中的UUID以Microsoft的全局唯一标识符GUID的形式出现,这些标识符在Microsoft的组件对象模型[COM]中使用。

UUID以各种变体生成:最初大多数是从计算机的MAC派生的,随后使用了基于name的散列值。关于这个问题,比如有多少UUID,有多大概率会生成一个已有的UUID,这是来自维基百科上 UUID 的文章的一些数字:

在100年里,每秒生成十亿个UUID,生成重复的UUID的概率约为50%。如果每个人都有6亿个UUID,下一个UUID重复的概率约为50%。

fstab中的用法

就像之前提到的,UUID在Linux下被经常用于标识块设备。想象一下,你有两个硬盘通过USB连接上,它们不是持久存储,只能依赖两个设备的名字来区分:有时第一个USB硬盘是“sda”,有时它是“sdb”。所以要唯一寻址正确的磁盘,比如在 /etc/fstab 中,你必须添加如下条目:

UUID=9043278a-1817-4ff5-8145-c79d8e24ea79 /boot ext3 defaults 0 2

对于块设备,uuid是存储在超级块中的。

但请注意,当您使用LVM快照时,不应在fstab中使用UUID。

有关更多详细信息,请参阅下面的“何时不使用它们”。

Linux下的实现和生成

在Linux下UUID在file中生成,你可以通过 /drivers/char/random.c 来生成新的UUID:

1
2
$ cat /proc/sys/kernel/random/uuid
eaf3a162-d770-4ec9-a819-ec96d429ea9f

uuidgen,以及ext 2/3/4 工具 E2fsprogs 使用程序库 libuuid 来生成UUID:

1
2
$ uuidgen
f81cc383-aa75-4714-aa8a-3ce39e8ad33c

Bash中如何得到UUID

UUID中最有趣的部分很可能是如何获取硬盘的当前UUID。

如前面已经提到的,有两种主要的方法来获取它们:在特殊目录中的 ls 命令和工具 blkid。

第一,在 /dev/disk/by-uuid 中执行 ls 命令。这个目录包含了名字为UUID,链接到“真正的”块设备文件。对于你很难辨别安装了什么磁盘的情况下,这是很方便的。

1
2
$ ls -l /dev/disk/by-uuid
lrwxrwxrwx 1 root root 10 11. Oct 18:02 53cdad3b-4b01-4a6c-a099-be1cdf1acf6d -> ../../sda2

第二,blkid 工具是util-linux软件包的一部分。它提供了一个界面来查询特定设备,并且还支持搜索标签。

1
2
3
4
5
$ blkid /dev/sda1
/dev/sda1: LABEL="/" UUID="ee7cf0a0-1922-401b-a1ae-6ec9261484c0" SEC_TYPE="ext2" TYPE="ext3"

这儿还有更多方法!让我们安装 hwinfo:

$ hwinfo –block
[…]
UDI: /org/freedesktop/Hal/devices/volume_uuid_3e953ee0_79f2_4d94_98b3_5f49ad652b7c
[…]
Device Files: […] /dev/disk/by-uuid/3e953ee0-79f2-4d94-98b3-5f49ad652b7c
[…]

1
2
3
4
5
6
7
8
9
10
11

就像你看到的,hwinfo列出了大量有关硬件的数据——包括设备的UUID。当你获取更多关于块设备的信息时使用它。

或者 udevadm?它是udev提供的、从udev数据库查询数据的工具。udev数据库包含了udev系统的所有信息,因此UUID信息只是一部分。如果你正在写一个“现代”的脚本,它很好地与Linux标准工具集成,我想我会使用udev。但是对于快速直接的、一次性的命令行工具,和`hwinfo`一样,它包含了太多的信息。

```shell
$ udevadm info -q all -n /dev/sda1|grep uuid
S: disk/by-uuid/9043278a-1817-4ff5-8145-c79d8e24ea79
E: [...] /dev/disk/by-uuid/9043278a-1817-4ff5-8145-c79d8e24ea79
E: ID_FS_UUID=9043278a-1817-4ff5-8145-c79d8e24ea79
E: ID_FS_UUID_ENC=9043278a-1817-4ff5-8145-c79d8e24ea79

在这种情况下,有时也提到udevinfo。但是,它已被弃用,大多数发行版不再包含。另外,另一种常提到的检索UUID的方法是从程序库 /lib/vol/vol_id。但是如bug #476379所述,vol_id只是一个私有的udev函数。因为此接口不稳定,它不应该被外部程序(或人)使用。此外,整个库可能会在将来删除——实际上已在某些发行版中删除了。

另外一种能查看很多磁盘信息的的工具是dumpe2fs。它输出所选文件系统的超级块和块组信息,因此也包括uuid:

1
2
3
$ sudo dumpe2fs /dev/dm-0|grep UUID
dumpe2fs 1.44.2 (14-May-2018)
Filesystem UUID: 11aef60d-3d80-49d8-aa7b-bf3510d946cb

谢谢 Greg 提供这个技巧!

也不要忘记lsblk。它在shell中有一个很好的结构化输出,不仅提供UUID,还提供目录、可用存储等等。这个命令的优点是,它是非常容易识别哪个磁盘包括哪个UUID:

1
2
3
4
5
6
7
8
9
10
11
12
$ lsblk -f
NAME FSTYPE LABEL UUID FSAVAIL FSUSE% MOUNTPOINT
nvme0n1

├─nvme0n1p1
│ vfat 6972-1366 633,8M 3% /boot/efi
├─nvme0n1p2
│ ext4 5b62c867-016d-492d-b8a0-e50baf353952 715,1M 20% /boot
├─nvme0n1p3
│ crypto f1859e2a-acfa-49a8-b9e4-bf3d9dec4208
│ └─luks-f1859e2a-acfa-49a8-b9e4-bf3d9dec4208
│ ext4 4e385121-f4b0-4d91-86fe-26119c25c8b4 141,2G 14% /home

谢谢 __ :~) __bernard 提供这个技巧。

如何在GUI程序中获取UUID

如果你不善于使用shell,KDE-GUI工具也可以用来查找UUID:/usr/bin/kcmshell4 devinfo

设置UUID

就像评论中提到的,设置UUID有时也是必要的。因为UUID是超级块的一部分,所以根据文件系统的不同,可能要使用不同的工具。比如ext文件系统可以使用tune2fs:

1
# tune2fs -U new_uuid /dev/sdaX

什么时候不使用UUID

Zhenech 提到,并不是所有的地方都适合使用UUID。

因为挂载两个具有相同的UUID的文件系统是不可行的,所以需要额外关注LVM快照(或者克隆磁盘):因为具有同样的UUID,它们可能会挂载失败。

1
XFS: Filesystem dm-2 has duplicate UUID - can't mount

处理该问题的一种方法是更改UUID,另一种办法是挂载的时候带上nouuid选项。

注意,Btrfs在这里是不同的,因为您可能挂载多个子卷,所有子卷都来自一个不同的主UUID, Ben指出

作者

Robert Lu

发布于

2017-02-26

许可协议

评论